• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2008 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.app.cts;
18 
19 import static android.Manifest.permission.POST_NOTIFICATIONS;
20 import static android.Manifest.permission.REVOKE_POST_NOTIFICATIONS_WITHOUT_KILL;
21 import static android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS;
22 import static android.app.stubs.LocalForegroundService.COMMAND_START_FOREGROUND;
23 import static android.app.stubs.LocalForegroundService.COMMAND_START_FOREGROUND_DEFER_NOTIFICATION;
24 import static android.app.stubs.LocalForegroundService.COMMAND_STOP_FOREGROUND_DETACH_NOTIFICATION;
25 import static android.app.stubs.LocalForegroundService.COMMAND_STOP_FOREGROUND_DONT_REMOVE_NOTIFICATION;
26 
27 import android.app.Activity;
28 import android.app.ActivityManager;
29 import android.app.Notification;
30 import android.app.NotificationChannel;
31 import android.app.NotificationManager;
32 import android.app.PendingIntent;
33 import android.app.stubs.ActivityTestsBase;
34 import android.app.stubs.IsolatedService;
35 import android.app.stubs.LaunchpadActivity;
36 import android.app.stubs.LocalDeniedService;
37 import android.app.stubs.LocalForegroundService;
38 import android.app.stubs.LocalGrantedService;
39 import android.app.stubs.LocalPhoneCallService;
40 import android.app.stubs.LocalService;
41 import android.app.stubs.LocalStoppedService;
42 import android.app.stubs.NullService;
43 import android.app.stubs.R;
44 import android.content.ComponentName;
45 import android.content.Context;
46 import android.content.Intent;
47 import android.content.ServiceConnection;
48 import android.content.pm.ServiceInfo;
49 import android.os.Binder;
50 import android.os.Bundle;
51 import android.os.Handler;
52 import android.os.HandlerThread;
53 import android.os.IBinder;
54 import android.os.Parcel;
55 import android.os.ParcelFileDescriptor;
56 import android.os.Process;
57 import android.os.RemoteException;
58 import android.os.SystemClock;
59 import android.os.UserHandle;
60 import android.permission.PermissionManager;
61 import android.permission.cts.PermissionUtils;
62 import android.platform.test.annotations.Presubmit;
63 import android.service.notification.StatusBarNotification;
64 import android.test.suitebuilder.annotation.MediumTest;
65 import android.util.Log;
66 import android.util.SparseArray;
67 
68 import androidx.test.InstrumentationRegistry;
69 import androidx.test.filters.FlakyTest;
70 
71 import com.android.compatibility.common.util.DeviceConfigStateHelper;
72 import com.android.compatibility.common.util.IBinderParcelable;
73 import com.android.compatibility.common.util.SystemUtil;
74 import com.android.server.am.nano.ActivityManagerServiceDumpProcessesProto;
75 import com.android.server.am.nano.ProcessRecordProto;
76 
77 import com.google.protobuf.nano.InvalidProtocolBufferNanoException;
78 
79 import java.io.ByteArrayOutputStream;
80 import java.io.FileInputStream;
81 import java.io.IOException;
82 import java.util.ArrayList;
83 import java.util.List;
84 import java.util.concurrent.CountDownLatch;
85 import java.util.concurrent.Executor;
86 import java.util.concurrent.TimeUnit;
87 
88 @Presubmit
89 public class ServiceTest extends ActivityTestsBase {
90     private static final String TAG = "ServiceTest";
91     private static final String NOTIFICATION_CHANNEL_ID = TAG;
92     private static final int STATE_START_1 = 0;
93     private static final int STATE_START_2 = 1;
94     private static final int STATE_START_3 = 2;
95     private static final int STATE_UNBIND = 3;
96     private static final int STATE_DESTROY = 4;
97     private static final int STATE_REBIND = 5;
98     private static final int STATE_UNBIND_ONLY = 6;
99     private static final int STATE_STOP_SELF_SUCCESS_UNBIND = 6;
100     private static final int DELAY = 5000;
101     private static final
102         String EXIST_CONN_TO_RECEIVE_SERVICE = "existing connection to receive service";
103     private static final String EXIST_CONN_TO_LOSE_SERVICE = "existing connection to lose service";
104     private static final String EXTERNAL_SERVICE_PACKAGE = "com.android.app2";
105     private static final String EXTERNAL_SERVICE_COMPONENT =
106             EXTERNAL_SERVICE_PACKAGE + "/android.app.stubs.LocalService";
107     private static final String DELAYED_SERVICE_PACKAGE = "com.android.delayed_start";
108     private static final String DELAYED_SERVICE_COMPONENT =
109             DELAYED_SERVICE_PACKAGE + "/android.app.stubs.LocalService";
110     private static final String APP_ZYGOTE_PROCESS_NAME = "android.app.stubs_zygote";
111     private static final String KEY_MAX_SERVICE_CONNECTIONS_PER_PROCESS =
112             "max_service_connections_per_process";
113     private int mExpectedServiceState;
114     private Context mContext;
115     private Intent mLocalService;
116     private Intent mLocalDeniedService;
117     private Intent mLocalForegroundService;
118     private Intent mLocalPhoneCallService;
119     private Intent mLocalGrantedService;
120     private Intent mLocalService_ApplicationHasPermission;
121     private Intent mLocalService_ApplicationDoesNotHavePermission;
122     private Intent mIsolatedService;
123     private Intent mExternalService;
124     private Intent mDelayedService;
125     private Executor mContextMainExecutor;
126     private HandlerThread mBackgroundThread;
127     private Executor mBackgroundThreadExecutor;
128 
129     private IBinder mStateReceiver;
130 
131     private static class EmptyConnection implements ServiceConnection {
132         @Override
onServiceConnected(ComponentName name, IBinder service)133         public void onServiceConnected(ComponentName name, IBinder service) {
134         }
135 
136         @Override
onServiceDisconnected(ComponentName name)137         public void onServiceDisconnected(ComponentName name) {
138         }
139     }
140 
141     private static class NullServiceConnection implements ServiceConnection {
142         boolean mNullBinding = false;
143 
onServiceConnected(ComponentName name, IBinder service)144         @Override public void onServiceConnected(ComponentName name, IBinder service) {}
onServiceDisconnected(ComponentName name)145         @Override public void onServiceDisconnected(ComponentName name) {}
146 
147         @Override
onNullBinding(ComponentName name)148         public void onNullBinding(ComponentName name) {
149             synchronized (this) {
150                 mNullBinding = true;
151                 this.notifyAll();
152             }
153         }
154 
waitForNullBinding(final long timeout)155         public void waitForNullBinding(final long timeout) {
156             long now = SystemClock.uptimeMillis();
157             final long end = now + timeout;
158             synchronized (this) {
159                 while (!mNullBinding && (now < end)) {
160                     try {
161                         this.wait(end - now);
162                     } catch (InterruptedException e) {
163                     }
164                     now = SystemClock.uptimeMillis();
165                 }
166             }
167         }
168 
nullBindingReceived()169         public boolean nullBindingReceived() {
170             synchronized (this) {
171                 return mNullBinding;
172             }
173         }
174     }
175 
176     private static class LatchedConnection implements ServiceConnection {
177         private final CountDownLatch mLatch;
178 
LatchedConnection(CountDownLatch latch)179         LatchedConnection(CountDownLatch latch) {
180             mLatch = latch;
181         }
182 
183         @Override
onServiceConnected(ComponentName name, IBinder service)184         public void onServiceConnected(ComponentName name, IBinder service) {
185             mLatch.countDown();
186         }
187 
188         @Override
onServiceDisconnected(ComponentName name)189         public void onServiceDisconnected(ComponentName name) {
190         }
191     }
192 
193     private class TestConnection implements ServiceConnection {
194         private final boolean mExpectDisconnect;
195         private final boolean mSetReporter;
196         private boolean mMonitor;
197         private int mCount;
198         private Thread mOnServiceConnectedThread;
199 
TestConnection(boolean expectDisconnect, boolean setReporter)200         public TestConnection(boolean expectDisconnect, boolean setReporter) {
201             mExpectDisconnect = expectDisconnect;
202             mSetReporter = setReporter;
203             mMonitor = !setReporter;
204         }
205 
setMonitor(boolean v)206         void setMonitor(boolean v) {
207             mMonitor = v;
208         }
209 
getOnServiceConnectedThread()210         public Thread getOnServiceConnectedThread() {
211             return mOnServiceConnectedThread;
212         }
213 
214         @Override
onServiceConnected(ComponentName name, IBinder service)215         public void onServiceConnected(ComponentName name, IBinder service) {
216             mOnServiceConnectedThread = Thread.currentThread();
217             if (mSetReporter) {
218                 Parcel data = Parcel.obtain();
219                 data.writeInterfaceToken(LocalService.SERVICE_LOCAL);
220                 data.writeStrongBinder(mStateReceiver);
221                 try {
222                     service.transact(LocalService.SET_REPORTER_CODE, data, null, 0);
223                 } catch (RemoteException e) {
224                     finishBad("DeadObjectException when sending reporting object");
225                 }
226                 data.recycle();
227             }
228 
229             if (mMonitor) {
230                 mCount++;
231                 if (mExpectedServiceState == STATE_START_1) {
232                     if (mCount == 1) {
233                         finishGood();
234                     } else {
235                         finishBad("onServiceConnected() again on an object when it "
236                                 + "should have been the first time");
237                     }
238                 } else if (mExpectedServiceState == STATE_START_2) {
239                     if (mCount == 2) {
240                         finishGood();
241                     } else {
242                         finishBad("onServiceConnected() the first time on an object "
243                                 + "when it should have been the second time");
244                     }
245                 } else {
246                     finishBad("onServiceConnected() called unexpectedly");
247                 }
248             }
249         }
250 
251         @Override
onServiceDisconnected(ComponentName name)252         public void onServiceDisconnected(ComponentName name) {
253             if (mMonitor) {
254                 if (mExpectedServiceState == STATE_DESTROY) {
255                     if (mExpectDisconnect) {
256                         finishGood();
257                     } else {
258                         finishBad("onServiceDisconnected() when it shouldn't have been");
259                     }
260                 } else {
261                     finishBad("onServiceDisconnected() called unexpectedly");
262                 }
263             }
264         }
265     }
266 
267     private class TestStopSelfConnection extends TestConnection {
268         private IBinder mService;
269 
TestStopSelfConnection()270         public TestStopSelfConnection() {
271             super(false /* expectDisconnect */, true /* setReporter */);
272         }
273 
executeTransact(int code)274         private void executeTransact(int code) {
275             Parcel data = Parcel.obtain();
276             data.writeInterfaceToken(LocalService.SERVICE_LOCAL);
277             try {
278                 mService.transact(code, data, null /* reply */, 0);
279             } catch (RemoteException e) {
280                 finishBad("DeadObjectException when sending reporting object");
281             }
282             data.recycle();
283         }
284 
stopSelf()285         public void stopSelf() {
286             executeTransact(LocalService.STOP_SELF_CODE);
287         }
288 
stopSelfResult()289         public void stopSelfResult() {
290             executeTransact(LocalService.STOP_SELF_RESULT_CODE);
291         }
292 
293         @Override
onServiceConnected(ComponentName name, IBinder service)294         public void onServiceConnected(ComponentName name, IBinder service) {
295             mService = service;
296             super.onServiceConnected(name, service);
297         }
298 
299         @Override
onServiceDisconnected(ComponentName name)300         public void onServiceDisconnected(ComponentName name) {
301             synchronized (this) {
302                 mService = null;
303             }
304         }
305     }
306 
307     final class IsolatedConnection implements ServiceConnection {
308         private IBinder mService;
309         private int mUid;
310         private int mPid;
311         private int mPpid;
312         private Thread mOnServiceConnectedThread;
313 
IsolatedConnection()314         public IsolatedConnection() {
315             mUid = mPid = -1;
316         }
317 
waitForService(int timeoutMs)318         public void waitForService(int timeoutMs) {
319             final long endTime = System.currentTimeMillis() + timeoutMs;
320 
321             boolean timeout = false;
322             synchronized (this) {
323                 while (mService == null) {
324                     final long delay = endTime - System.currentTimeMillis();
325                     if (delay < 0) {
326                         timeout = true;
327                         break;
328                     }
329 
330                     try {
331                         wait(delay);
332                     } catch (final java.lang.InterruptedException e) {
333                         // do nothing
334                     }
335                 }
336             }
337 
338             if (timeout) {
339                 throw new RuntimeException("Timed out waiting for connection");
340             }
341         }
342 
getUid()343         public int getUid() {
344             return mUid;
345         }
346 
getPid()347         public int getPid() {
348             return mPid;
349         }
350 
getPpid()351         public int getPpid() {
352             return mPpid;
353         }
354 
zygotePreloadCalled()355         public boolean zygotePreloadCalled() {
356             Parcel data = Parcel.obtain();
357             Parcel reply = Parcel.obtain();
358             data.writeInterfaceToken(LocalService.SERVICE_LOCAL);
359             try {
360                 mService.transact(LocalService.GET_ZYGOTE_PRELOAD_CALLED, data, reply, 0);
361             } catch (RemoteException e) {
362                 finishBad("DeadObjectException when sending reporting object");
363             }
364             boolean value = reply.readBoolean();
365             reply.recycle();
366             data.recycle();
367             return value;
368         }
369 
setValue(int value)370         public void setValue(int value) {
371             Parcel data = Parcel.obtain();
372             data.writeInterfaceToken(LocalService.SERVICE_LOCAL);
373             data.writeInt(value);
374             try {
375                 mService.transact(LocalService.SET_VALUE_CODE, data, null, 0);
376             } catch (RemoteException e) {
377                 finishBad("DeadObjectException when sending reporting object");
378             }
379             data.recycle();
380         }
381 
getValue(int transactCode)382         public int getValue(int transactCode) {
383             Parcel data = Parcel.obtain();
384             Parcel reply = Parcel.obtain();
385             data.writeInterfaceToken(LocalService.SERVICE_LOCAL);
386             try {
387                 mService.transact(transactCode, data, reply, 0);
388             } catch (RemoteException e) {
389                 finishBad("DeadObjectException when sending reporting object");
390             }
391             int value = reply.readInt();
392             reply.recycle();
393             data.recycle();
394             return value;
395         }
396 
getValue()397         public int getValue() {
398             return getValue(LocalService.GET_VALUE_CODE);
399         }
400 
getPidIpc()401         public int getPidIpc() {
402             return getValue(LocalService.GET_PID_CODE);
403         }
404 
getPpidIpc()405         public int getPpidIpc() {
406             return getValue(LocalService.GET_PPID_CODE);
407         }
408 
getUidIpc()409         public int getUidIpc() {
410             return getValue(LocalService.GET_UID_CODE);
411         }
412 
getOnServiceConnectedThread()413         public Thread getOnServiceConnectedThread() {
414             return mOnServiceConnectedThread;
415         }
416 
getOnCreateCalledCount()417         public int getOnCreateCalledCount() {
418             return getValue(LocalService.GET_ON_CREATE_CALLED_COUNT);
419         }
420 
421         @Override
onServiceConnected(ComponentName name, IBinder service)422         public void onServiceConnected(ComponentName name, IBinder service) {
423             synchronized (this) {
424                 mOnServiceConnectedThread = Thread.currentThread();
425                 mService = service;
426                 mUid = getUidIpc();
427                 mPid = getPidIpc();
428                 mPpid = getPpidIpc();
429                 notifyAll();
430             }
431         }
432 
433         @Override
onServiceDisconnected(ComponentName name)434         public void onServiceDisconnected(ComponentName name) {
435             synchronized (this) {
436                 mService = null;
437             }
438         }
439     }
440 
executeShellCommand(String cmd)441     private byte[] executeShellCommand(String cmd) {
442         try {
443             ParcelFileDescriptor pfd =
444                     InstrumentationRegistry.getInstrumentation().getUiAutomation()
445                             .executeShellCommand(cmd);
446             byte[] buf = new byte[512];
447             int bytesRead;
448             FileInputStream fis = new ParcelFileDescriptor.AutoCloseInputStream(pfd);
449             ByteArrayOutputStream stdout = new ByteArrayOutputStream();
450             while ((bytesRead = fis.read(buf)) != -1) {
451                 stdout.write(buf, 0, bytesRead);
452             }
453             fis.close();
454             return stdout.toByteArray();
455         } catch (IOException e) {
456             throw new RuntimeException(e);
457         }
458     }
459 
getActivityManagerProcesses()460     public ActivityManagerServiceDumpProcessesProto getActivityManagerProcesses() {
461         byte[] dump = executeShellCommand("dumpsys activity --proto processes");
462         try {
463             return ActivityManagerServiceDumpProcessesProto.parseFrom(dump);
464         } catch (InvalidProtocolBufferNanoException e) {
465             throw new RuntimeException("Failed parsing proto", e);
466         }
467     }
468 
startExpectResult(Intent service)469     private void startExpectResult(Intent service) {
470         startExpectResult(service, new Bundle());
471     }
472 
startExpectResult(Intent service, Bundle bundle)473     private void startExpectResult(Intent service, Bundle bundle) {
474         bundle.putParcelable(LocalService.REPORT_OBJ_NAME, new IBinderParcelable(mStateReceiver));
475 
476         boolean success = false;
477         try {
478             mExpectedServiceState = STATE_START_1;
479             mContext.startService(new Intent(service).putExtras(bundle));
480             waitForResultOrThrow(DELAY, "service to start first time");
481             mExpectedServiceState = STATE_START_2;
482             mContext.startService(new Intent(service).putExtras(bundle));
483             waitForResultOrThrow(DELAY, "service to start second time");
484             success = true;
485         } finally {
486             if (!success) {
487                 mContext.stopService(service);
488             }
489         }
490         mExpectedServiceState = STATE_DESTROY;
491         mContext.stopService(service);
492         waitForResultOrThrow(DELAY, "service to be destroyed");
493     }
494 
getNotificationManager()495     private NotificationManager getNotificationManager() {
496         NotificationManager notificationManager =
497                 (NotificationManager) getContext().getSystemService(Context.NOTIFICATION_SERVICE);
498         return notificationManager;
499     }
500 
sendNotification(int id, String title)501     private void sendNotification(int id, String title) {
502         Notification notification = new Notification.Builder(getContext(), NOTIFICATION_CHANNEL_ID)
503             .setContentTitle(title)
504             .setSmallIcon(R.drawable.black)
505             .build();
506         getNotificationManager().notify(id, notification);
507     }
508 
cancelNotification(int id)509     private void cancelNotification(int id) {
510         getNotificationManager().cancel(id);
511     }
512 
assertNotification(int id, String expectedTitle, boolean shouldHaveFgsFlag)513     private void assertNotification(int id, String expectedTitle, boolean shouldHaveFgsFlag) {
514         String packageName = getContext().getPackageName();
515         String titleErrorMsg = null;
516         String flagErrorMsg = null;
517         int i = 0;
518         while (true) {
519             titleErrorMsg = null;
520             flagErrorMsg = null;
521             StatusBarNotification[] sbns = getNotificationManager().getActiveNotifications();
522             for (StatusBarNotification sbn : sbns) {
523                 if (sbn.getId() == id && sbn.getPackageName().equals(packageName)) {
524                     Notification n = sbn.getNotification();
525                     // check title first to make sure the update has propagated
526                     String actualTitle = n.extras.getString(Notification.EXTRA_TITLE);
527                     if (expectedTitle.equals(actualTitle)) {
528                         titleErrorMsg = null;
529                         // make sure notification and service state is in sync
530                         if (shouldHaveFgsFlag ==
531                                 ((n.flags & Notification.FLAG_FOREGROUND_SERVICE) != 0)) {
532                             flagErrorMsg = null;
533                             // both title and flag matches.
534                             return;
535                         } else {
536                             // title match, flag not match.
537                             flagErrorMsg = String.format("Wrong flag for notification #%d: "
538                                     + " actual '%d'", id, n.flags);
539                         }
540                     } else {
541                         // It's possible the notification hasn't been updated yet, so save the error
542                         // message to only fail after retrying.
543                         titleErrorMsg = String.format("Wrong title for notification #%d: "
544                                 + "expected '%s', actual '%s'", id, expectedTitle, actualTitle);
545                     }
546                     // id and packageName are found, break now.
547                     break;
548                 }
549             }
550             // allow two more retries.
551             if (++i > 2) {
552                 break;
553             }
554             // Notification might not be rendered yet, wait and try again...
555             SystemClock.sleep(DELAY); // 5 seconds delay
556         }
557         if (flagErrorMsg != null) {
558             fail(flagErrorMsg);
559         }
560         if (titleErrorMsg != null) {
561             fail(titleErrorMsg);
562         }
563         fail("No notification with id " + id + " for package " + packageName);
564     }
565 
assertNoNotification(int id)566     private void assertNoNotification(int id) {
567         String packageName = getContext().getPackageName();
568         StatusBarNotification found = null;
569         for (int i = 1; i<=2; i++) {
570             found = null;
571             StatusBarNotification[] sbns = getNotificationManager().getActiveNotifications();
572             for (StatusBarNotification sbn : sbns) {
573                 if (sbn.getId() == id && sbn.getPackageName().equals(packageName)) {
574                     found = sbn;
575                     break;
576                 }
577             }
578             if (found != null) {
579                 // Notification might not be canceled yet, wait and try again...
580                 try {
581                     Thread.sleep(DELAY);
582                 } catch (InterruptedException e) {
583                     Thread.currentThread().interrupt();
584                 }
585             }
586         }
587         assertNull("Found notification with id " + id + " for package " + packageName + ": "
588                 + found, found);
589     }
590 
591     /**
592      * test the service lifecycle, a service can be used in two ways:
593      * 1  It can be started and allowed to run until someone stops it or it stops itself.
594      *    In this mode, it's started by calling Context.startService()
595      *    and stopped by calling Context.stopService().
596      *    It can stop itself by calling Service.stopSelf() or Service.stopSelfResult().
597      *    Only one stopService() call is needed to stop the service,
598      *    no matter how many times startService() was called.
599      * 2  It can be operated programmatically using an interface that it defines and exports.
600      *    Clients establish a connection to the Service object
601      *    and use that connection to call into the service.
602      *    The connection is established by calling Context.bindService(),
603      *    and is closed by calling Context.unbindService().
604      *    Multiple clients can bind to the same service.
605      *    If the service has not already been launched, bindService() can optionally launch it.
606      */
bindExpectResult(Intent service)607     private void bindExpectResult(Intent service) {
608         TestConnection conn = new TestConnection(true, false);
609         TestConnection conn2 = new TestConnection(false, false);
610         boolean success = false;
611         try {
612             // Expect to see the TestConnection connected.
613             mExpectedServiceState = STATE_START_1;
614             mContext.bindService(service, conn, 0);
615             mContext.startService(service);
616             waitForResultOrThrow(DELAY, EXIST_CONN_TO_RECEIVE_SERVICE);
617 
618             // Expect to see the second TestConnection connected.
619             mContext.bindService(service, conn2, 0);
620             waitForResultOrThrow(DELAY, "new connection to receive service");
621 
622             mContext.unbindService(conn2);
623             success = true;
624         } finally {
625             if (!success) {
626                 mContext.unbindService(conn);
627                 mContext.unbindService(conn2);
628                 mContext.stopService(service);
629             }
630         }
631 
632         // Expect to see the TestConnection disconnected.
633         mExpectedServiceState = STATE_DESTROY;
634         mContext.stopService(service);
635         waitForResultOrThrow(DELAY, EXIST_CONN_TO_LOSE_SERVICE);
636 
637         mContext.unbindService(conn);
638 
639         conn = new TestConnection(true, true);
640         success = false;
641         try {
642             // Expect to see the TestConnection connected.
643             conn.setMonitor(true);
644             mExpectedServiceState = STATE_START_1;
645             mContext.bindService(service, conn, 0);
646             mContext.startService(service);
647             waitForResultOrThrow(DELAY, EXIST_CONN_TO_RECEIVE_SERVICE);
648 
649             success = true;
650         } finally {
651             if (!success) {
652                 mContext.unbindService(conn);
653                 mContext.stopService(service);
654             }
655         }
656 
657         // Expect to see the service unbind and then destroyed.
658         conn.setMonitor(false);
659         mExpectedServiceState = STATE_UNBIND;
660         mContext.stopService(service);
661         waitForResultOrThrow(DELAY, EXIST_CONN_TO_LOSE_SERVICE);
662 
663         mContext.unbindService(conn);
664 
665         conn = new TestConnection(true, true);
666         success = false;
667         try {
668             // Expect to see the TestConnection connected.
669             conn.setMonitor(true);
670             mExpectedServiceState = STATE_START_1;
671             mContext.bindService(service, conn, 0);
672             mContext.startService(service);
673             waitForResultOrThrow(DELAY, EXIST_CONN_TO_RECEIVE_SERVICE);
674 
675             success = true;
676         } finally {
677             if (!success) {
678                 mContext.unbindService(conn);
679                 mContext.stopService(service);
680             }
681         }
682 
683         // Expect to see the service unbind but not destroyed.
684         conn.setMonitor(false);
685         mExpectedServiceState = STATE_UNBIND_ONLY;
686         mContext.unbindService(conn);
687         waitForResultOrThrow(DELAY, "existing connection to unbind service");
688 
689         // Expect to see the service rebound.
690         mExpectedServiceState = STATE_REBIND;
691         mContext.bindService(service, conn, 0);
692         waitForResultOrThrow(DELAY, "existing connection to rebind service");
693 
694         // Expect to see the service unbind and then destroyed.
695         mExpectedServiceState = STATE_UNBIND;
696         mContext.stopService(service);
697         waitForResultOrThrow(DELAY, EXIST_CONN_TO_LOSE_SERVICE);
698 
699         mContext.unbindService(conn);
700     }
701 
702     /**
703      * test automatically create the service as long as the binding exists
704      * and disconnect from an application service
705      */
bindAutoExpectResult(Intent service)706     private void bindAutoExpectResult(Intent service) {
707         TestConnection conn = new TestConnection(false, true);
708         boolean success = false;
709         try {
710             conn.setMonitor(true);
711             mExpectedServiceState = STATE_START_1;
712             mContext.bindService(
713                     service, conn, Context.BIND_AUTO_CREATE);
714             waitForResultOrThrow(DELAY, "connection to start and receive service");
715             success = true;
716         } finally {
717             if (!success) {
718                 mContext.unbindService(conn);
719             }
720         }
721         mExpectedServiceState = STATE_UNBIND;
722         mContext.unbindService(conn);
723         waitForResultOrThrow(DELAY, "disconnecting from service");
724     }
725 
726     @Override
setUp()727     protected void setUp() throws Exception {
728         super.setUp();
729         mContext = getContext();
730         PermissionUtils.grantPermission(mContext.getPackageName(), POST_NOTIFICATIONS);
731         mLocalService = new Intent(mContext, LocalService.class);
732         mExternalService = new Intent();
733         mDelayedService = new Intent();
734         mExternalService.setComponent(ComponentName.unflattenFromString(EXTERNAL_SERVICE_COMPONENT));
735         mDelayedService.setComponent(ComponentName.unflattenFromString(DELAYED_SERVICE_COMPONENT));
736         mLocalForegroundService = new Intent(mContext, LocalForegroundService.class);
737         mLocalPhoneCallService = new Intent(mContext, LocalPhoneCallService.class);
738         mLocalPhoneCallService.putExtra(LocalForegroundService.EXTRA_FOREGROUND_SERVICE_TYPE,
739                 ServiceInfo.FOREGROUND_SERVICE_TYPE_PHONE_CALL);
740         mLocalDeniedService = new Intent(mContext, LocalDeniedService.class);
741         mLocalGrantedService = new Intent(mContext, LocalGrantedService.class);
742         mLocalService_ApplicationHasPermission = new Intent(
743                 LocalService.SERVICE_LOCAL_GRANTED, null /*uri*/, mContext, LocalService.class);
744         mLocalService_ApplicationDoesNotHavePermission = new Intent(
745                 LocalService.SERVICE_LOCAL_DENIED, null /*uri*/, mContext, LocalService.class);
746         mIsolatedService = new Intent(mContext, IsolatedService.class);
747         mStateReceiver = new MockBinder();
748         getNotificationManager().createNotificationChannel(new NotificationChannel(
749                 NOTIFICATION_CHANNEL_ID, "name", NotificationManager.IMPORTANCE_DEFAULT));
750         mContextMainExecutor = mContext.getMainExecutor();
751         executeShellCommand("cmd activity fgs-notification-rate-limit disable");
752     }
753 
setupBackgroundThread()754     private void setupBackgroundThread() {
755         HandlerThread thread  = new HandlerThread("ServiceTestBackgroundThread");
756         thread.start();
757         Handler handler = new Handler(thread.getLooper());
758         mBackgroundThread = thread;
759         mBackgroundThreadExecutor = new Executor() {
760             @Override
761             public void execute(Runnable runnable) {
762                 handler.post(runnable);
763             }
764         };
765     }
766 
767     @Override
tearDown()768     protected void tearDown() throws Exception {
769         super.tearDown();
770         executeShellCommand("cmd activity fgs-notification-rate-limit enable");
771         getNotificationManager().deleteNotificationChannel(NOTIFICATION_CHANNEL_ID);
772         mContext.stopService(mLocalService);
773         mContext.stopService(mLocalForegroundService);
774         mContext.stopService(mLocalGrantedService);
775         mContext.stopService(mLocalService_ApplicationHasPermission);
776         mContext.stopService(mExternalService);
777         mContext.stopService(mDelayedService);
778         if (mBackgroundThread != null) {
779             mBackgroundThread.quitSafely();
780         }
781         mBackgroundThread = null;
782         mBackgroundThreadExecutor = null;
783         // Use test API to prevent PermissionManager from killing the test process when revoking
784         // permission.
785         SystemUtil.runWithShellPermissionIdentity(
786                 () -> mContext.getSystemService(PermissionManager.class)
787                         .revokePostNotificationPermissionWithoutKillForTest(
788                                 mContext.getPackageName(),
789                                 Process.myUserHandle().getIdentifier()),
790                 REVOKE_POST_NOTIFICATIONS_WITHOUT_KILL,
791                 REVOKE_RUNTIME_PERMISSIONS);
792     }
793 
794     private class MockBinder extends Binder {
795         @Override
onTransact(int code, Parcel data, Parcel reply, int flags)796         protected boolean onTransact(int code, Parcel data, Parcel reply,
797                 int flags) throws RemoteException {
798             if (code == LocalService.STARTED_CODE) {
799                 data.enforceInterface(LocalService.SERVICE_LOCAL);
800                 int count = data.readInt();
801                 if (mExpectedServiceState == STATE_START_1) {
802                     if (count == 1) {
803                         finishGood();
804                     } else {
805                         finishBad("onStart() again on an object when it "
806                                 + "should have been the first time");
807                     }
808                 } else if (mExpectedServiceState == STATE_START_2) {
809                     if (count == 2) {
810                         finishGood();
811                     } else {
812                         finishBad("onStart() the first time on an object when it "
813                                 + "should have been the second time");
814                     }
815                 } else if (mExpectedServiceState == STATE_START_3) {
816                     if (count == 3) {
817                         finishGood();
818                     } else {
819                         finishBad("onStart() the first time on an object when it "
820                                 + "should have been the third time");
821                     }
822                 } else {
823                     finishBad("onStart() was called when not expected (state="
824                             + mExpectedServiceState + ")");
825                 }
826                 return true;
827             } else if (code == LocalService.DESTROYED_CODE) {
828                 data.enforceInterface(LocalService.SERVICE_LOCAL);
829                 if (mExpectedServiceState == STATE_DESTROY) {
830                     finishGood();
831                 } else {
832                     finishBad("onDestroy() was called when not expected (state="
833                             + mExpectedServiceState + ")");
834                 }
835                 return true;
836             } else if (code == LocalService.UNBIND_CODE) {
837                 data.enforceInterface(LocalService.SERVICE_LOCAL);
838                 if (mExpectedServiceState == STATE_UNBIND) {
839                     mExpectedServiceState = STATE_DESTROY;
840                 } else if (mExpectedServiceState == STATE_UNBIND_ONLY) {
841                     finishGood();
842                 } else {
843                     finishBad("onUnbind() was called when not expected (state="
844                             + mExpectedServiceState + ")");
845                 }
846                 return true;
847             } else if (code == LocalService.REBIND_CODE) {
848                 data.enforceInterface(LocalService.SERVICE_LOCAL);
849                 if (mExpectedServiceState == STATE_REBIND) {
850                     finishGood();
851                 } else {
852                     finishBad("onRebind() was called when not expected (state="
853                             + mExpectedServiceState + ")");
854                 }
855                 return true;
856             } else if (code == LocalService.STOP_SELF_SUCCESS_UNBIND_CODE) {
857                 data.enforceInterface(LocalService.SERVICE_LOCAL);
858                 if (mExpectedServiceState == STATE_STOP_SELF_SUCCESS_UNBIND) {
859                     finishGood();
860                 } else {
861                     finishBad("onUnbind() was called when not expected (state="
862                             + mExpectedServiceState + ")");
863                 }
864                 return true;
865             } else {
866                 return super.onTransact(code, data, reply, flags);
867             }
868         }
869     }
870 
testStopSelf()871     public void testStopSelf() throws Exception {
872         TestStopSelfConnection conn = new TestStopSelfConnection();
873         boolean success = false;
874         final Intent service = new Intent(mContext, LocalStoppedService.class);
875         try {
876             conn.setMonitor(true);
877             mExpectedServiceState = STATE_START_1;
878             mContext.bindService(service, conn, 0);
879             mContext.startService(service);
880             waitForResultOrThrow(DELAY, EXIST_CONN_TO_RECEIVE_SERVICE);
881             success = true;
882         } finally {
883             if (!success) {
884                 mContext.unbindService(conn);
885                 mContext.stopService(service);
886             }
887         }
888         // Expect to see the service unbind and then destroyed.
889         mExpectedServiceState = STATE_UNBIND;
890         conn.stopSelf();
891         waitForResultOrThrow(DELAY, EXIST_CONN_TO_LOSE_SERVICE);
892 
893         mContext.unbindService(conn);
894     }
895 
testStopSelfResult()896     public void testStopSelfResult() throws Exception {
897         TestStopSelfConnection conn = new TestStopSelfConnection();
898         boolean success = false;
899         final Intent service = new Intent(mContext, LocalStoppedService.class);
900         try {
901             conn.setMonitor(true);
902             mExpectedServiceState = STATE_START_1;
903             mContext.bindService(service, conn, 0);
904             mContext.startService(service);
905             waitForResultOrThrow(DELAY, EXIST_CONN_TO_RECEIVE_SERVICE);
906             success = true;
907         } finally {
908             if (!success) {
909                 mContext.unbindService(conn);
910                 mContext.stopService(service);
911             }
912         }
913         // Expect to see the service unbind and then destroyed.
914         mExpectedServiceState = STATE_STOP_SELF_SUCCESS_UNBIND;
915         conn.stopSelfResult();
916         waitForResultOrThrow(DELAY, EXIST_CONN_TO_LOSE_SERVICE);
917 
918         mContext.unbindService(conn);
919     }
920 
testLocalStartClass()921     public void testLocalStartClass() throws Exception {
922         startExpectResult(mLocalService);
923     }
924 
testLocalStartAction()925     public void testLocalStartAction() throws Exception {
926         startExpectResult(new Intent(
927                 LocalService.SERVICE_LOCAL, null /*uri*/, mContext, LocalService.class));
928     }
929 
testLocalBindClass()930     public void testLocalBindClass() throws Exception {
931         bindExpectResult(mLocalService);
932     }
933 
testBindServiceWithExecutor()934     public void testBindServiceWithExecutor() throws Exception {
935       setupBackgroundThread();
936 
937       TestConnection conn = new TestConnection(true, false);
938       mExpectedServiceState = STATE_START_1;
939       mContext.bindService(
940           mLocalService, Context.BIND_AUTO_CREATE, mBackgroundThreadExecutor, conn);
941       waitForResultOrThrow(DELAY, EXIST_CONN_TO_RECEIVE_SERVICE);
942       assertEquals(mBackgroundThread, conn.getOnServiceConnectedThread());
943 
944       mContext.unbindService(conn);
945     }
946 
foregroundServiceIntent(Intent intent, int command)947     private Intent foregroundServiceIntent(Intent intent, int command) {
948         return new Intent(intent)
949                 .putExtras(LocalForegroundService.newCommand(mStateReceiver, command));
950     }
951 
952     /* Just the Intent for a foreground service */
foregroundServiceIntent(int command)953     private Intent foregroundServiceIntent(int command) {
954         return foregroundServiceIntent(mLocalForegroundService, command);
955     }
956 
startForegroundService(Intent intent, int command)957     private void startForegroundService(Intent intent, int command) {
958         mContext.startService(foregroundServiceIntent(intent, command));
959     }
960 
startForegroundService(int command)961     private void startForegroundService(int command) {
962         mContext.startService(foregroundServiceIntent(command));
963     }
964 
965     /* Start the service in a way that promises to go into the foreground */
startRequiredForegroundService(int command)966     private void startRequiredForegroundService(int command) {
967         mContext.startForegroundService(foregroundServiceIntent(command));
968     }
969 
970     @MediumTest
testForegroundService_canUpdateNotification()971     public void testForegroundService_canUpdateNotification() throws Exception {
972         boolean success = false;
973         try {
974             // Start service as foreground - it should show notification #1
975             mExpectedServiceState = STATE_START_1;
976             startForegroundService(COMMAND_START_FOREGROUND);
977             waitForResultOrThrow(DELAY, "service to start first time");
978             assertNotification(1, LocalForegroundService.getNotificationTitle(1), true);
979 
980             // Sends another notification reusing the same notification id.
981             String newTitle = "YODA I AM";
982             sendNotification(1, newTitle);
983             assertNotification(1, newTitle, true);
984 
985             success = true;
986         } finally {
987             if (!success) {
988                 mContext.stopService(mLocalForegroundService);
989             }
990         }
991         mExpectedServiceState = STATE_DESTROY;
992         mContext.stopService(mLocalForegroundService);
993         waitForResultOrThrow(DELAY, "service to be destroyed");
994         assertNoNotification(1);
995     }
996 
997     @MediumTest
testForegroundService_dontRemoveNotificationOnStop()998     public void testForegroundService_dontRemoveNotificationOnStop() throws Exception {
999         boolean success = false;
1000         try {
1001             // Start service as foreground - it should show notification #1
1002             mExpectedServiceState = STATE_START_1;
1003             startForegroundService(COMMAND_START_FOREGROUND);
1004             waitForResultOrThrow(DELAY, "service to start first time");
1005             assertNotification(1, LocalForegroundService.getNotificationTitle(1), true);
1006 
1007             // Stop foreground without removing notification - it should still show notification #1
1008             mExpectedServiceState = STATE_START_2;
1009             startForegroundService(COMMAND_STOP_FOREGROUND_DONT_REMOVE_NOTIFICATION);
1010             waitForResultOrThrow(DELAY, "service to stop foreground");
1011             assertNotification(1, LocalForegroundService.getNotificationTitle(1), false);
1012 
1013             // Sends another notification reusing the same notification id.
1014             String newTitle = "YODA I AM";
1015             sendNotification(1, newTitle);
1016             assertNotification(1, newTitle, false);
1017 
1018             // Start service as foreground again - it should kill notification #1 and show #2
1019             mExpectedServiceState = STATE_START_3;
1020             startForegroundService(COMMAND_START_FOREGROUND);
1021             waitForResultOrThrow(DELAY, "service to start foreground 2nd time");
1022             assertNoNotification(1);
1023             assertNotification(2, LocalForegroundService.getNotificationTitle(2), true);
1024 
1025             success = true;
1026         } finally {
1027             if (!success) {
1028                 mContext.stopService(mLocalForegroundService);
1029             }
1030         }
1031         mExpectedServiceState = STATE_DESTROY;
1032         mContext.stopService(mLocalForegroundService);
1033         waitForResultOrThrow(DELAY, "service to be destroyed");
1034         assertNoNotification(1);
1035         assertNoNotification(2);
1036     }
1037 
1038     @MediumTest
testForegroundService_removeNotificationOnStop()1039     public void testForegroundService_removeNotificationOnStop() throws Exception {
1040         testForegroundServiceRemoveNotificationOnStop(false);
1041     }
1042 
1043     @MediumTest
testForegroundService_removeNotificationOnStopUsingFlags()1044     public void testForegroundService_removeNotificationOnStopUsingFlags() throws Exception {
1045         testForegroundServiceRemoveNotificationOnStop(true);
1046     }
1047 
testForegroundServiceRemoveNotificationOnStop(boolean usingFlags)1048     private void testForegroundServiceRemoveNotificationOnStop(boolean usingFlags)
1049             throws Exception {
1050         boolean success = false;
1051         try {
1052             // Start service as foreground - it should show notification #1
1053             Log.d(TAG, "Expecting first start state...");
1054             mExpectedServiceState = STATE_START_1;
1055             startForegroundService(COMMAND_START_FOREGROUND);
1056             waitForResultOrThrow(DELAY, "service to start first time");
1057             assertNotification(1, LocalForegroundService.getNotificationTitle(1), true);
1058 
1059             // Stop foreground removing notification
1060             Log.d(TAG, "Expecting second start state...");
1061             mExpectedServiceState = STATE_START_2;
1062             if (usingFlags) {
1063                 startForegroundService(LocalForegroundService
1064                         .COMMAND_STOP_FOREGROUND_REMOVE_NOTIFICATION_USING_FLAGS);
1065             } else {
1066                 startForegroundService(LocalForegroundService
1067                         .COMMAND_STOP_FOREGROUND_REMOVE_NOTIFICATION);
1068             }
1069             waitForResultOrThrow(DELAY, "service to stop foreground");
1070             assertNoNotification(1);
1071 
1072             // Start service as foreground again - it should show notification #2
1073             mExpectedServiceState = STATE_START_3;
1074             startForegroundService(COMMAND_START_FOREGROUND);
1075             waitForResultOrThrow(DELAY, "service to start as foreground 2nd time");
1076             assertNotification(2, LocalForegroundService.getNotificationTitle(2), true);
1077 
1078             success = true;
1079         } finally {
1080             if (!success) {
1081                 mContext.stopService(mLocalForegroundService);
1082             }
1083         }
1084         mExpectedServiceState = STATE_DESTROY;
1085         mContext.stopService(mLocalForegroundService);
1086         waitForResultOrThrow(DELAY, "service to be destroyed");
1087         assertNoNotification(1);
1088         assertNoNotification(2);
1089     }
1090 
1091     @FlakyTest
testRunningServices()1092     public void testRunningServices() throws Exception {
1093         final int maxReturnedServices = 10;
1094         final Bundle bundle = new Bundle();
1095         bundle.putParcelable(LocalService.REPORT_OBJ_NAME, new IBinderParcelable(mStateReceiver));
1096 
1097         boolean success = false;
1098 
1099         ActivityManager am = mContext.getSystemService(ActivityManager.class);
1100 
1101         // Put target app on whitelist so we can start its services.
1102         SystemUtil.runShellCommand(InstrumentationRegistry.getInstrumentation(),
1103                 "cmd deviceidle whitelist +" + EXTERNAL_SERVICE_PACKAGE);
1104 
1105         // No services should be reported back at the beginning
1106         assertEquals(0, am.getRunningServices(maxReturnedServices).size());
1107         try {
1108             mExpectedServiceState = STATE_START_1;
1109             // Start external service.
1110             mContext.startService(new Intent(mExternalService).putExtras(bundle));
1111             waitForResultOrThrow(DELAY, "external service to start first time");
1112 
1113             // Ensure we can't see service.
1114             assertEquals(0, am.getRunningServices(maxReturnedServices).size());
1115 
1116             // Start local service.
1117             mContext.startService(new Intent(mLocalService).putExtras(bundle));
1118             waitForResultOrThrow(DELAY, "local service to start first time");
1119             success = true;
1120 
1121             // Ensure we can see service and it is ours.
1122             List<ActivityManager.RunningServiceInfo> services = am.getRunningServices(maxReturnedServices);
1123             assertEquals(1, services.size());
1124             assertEquals(android.os.Process.myUid(), services.get(0).uid);
1125         } finally {
1126             SystemUtil.runShellCommand(InstrumentationRegistry.getInstrumentation(),
1127                     "cmd deviceidle whitelist -" + EXTERNAL_SERVICE_PACKAGE);
1128             if (!success) {
1129                 mContext.stopService(mLocalService);
1130                 mContext.stopService(mExternalService);
1131             }
1132         }
1133         mExpectedServiceState = STATE_DESTROY;
1134 
1135         mContext.stopService(mExternalService);
1136         waitForResultOrThrow(DELAY, "external service to be destroyed");
1137 
1138         mContext.stopService(mLocalService);
1139         waitForResultOrThrow(DELAY, "local service to be destroyed");
1140 
1141         // Once our service has stopped, make sure we can't see any services.
1142         assertEquals(0, am.getRunningServices(maxReturnedServices).size());
1143     }
1144 
1145     @MediumTest
testForegroundService_detachNotificationOnStop()1146     public void testForegroundService_detachNotificationOnStop() throws Exception {
1147         String newTitle = null;
1148         boolean success = false;
1149         try {
1150 
1151             // Start service as foreground - it should show notification #1
1152             mExpectedServiceState = STATE_START_1;
1153             startForegroundService(COMMAND_START_FOREGROUND);
1154             waitForResultOrThrow(DELAY, "service to start first time");
1155             assertNotification(1, LocalForegroundService.getNotificationTitle(1), true);
1156 
1157             // Detaching notification
1158             mExpectedServiceState = STATE_START_2;
1159             startForegroundService(COMMAND_STOP_FOREGROUND_DETACH_NOTIFICATION);
1160             waitForResultOrThrow(DELAY, "service to stop foreground");
1161             assertNotification(1, LocalForegroundService.getNotificationTitle(1), false);
1162 
1163             // Sends another notification reusing the same notification id.
1164             newTitle = "YODA I AM";
1165             sendNotification(1, newTitle);
1166             assertNotification(1, newTitle, false);
1167 
1168             // Start service as foreground again - it should show notification #2..
1169             mExpectedServiceState = STATE_START_3;
1170             startForegroundService(COMMAND_START_FOREGROUND);
1171             waitForResultOrThrow(DELAY, "service to start as foreground 2nd time");
1172             assertNotification(2, LocalForegroundService.getNotificationTitle(2), true);
1173             //...but keeping notification #1
1174             assertNotification(1, newTitle, false);
1175 
1176             success = true;
1177         } finally {
1178             if (!success) {
1179                 mContext.stopService(mLocalForegroundService);
1180             }
1181         }
1182         mExpectedServiceState = STATE_DESTROY;
1183         mContext.stopService(mLocalForegroundService);
1184         waitForResultOrThrow(DELAY, "service to be destroyed");
1185         if (newTitle == null) {
1186             assertNoNotification(1);
1187         } else {
1188             assertNotification(1, newTitle, false);
1189             cancelNotification(1);
1190             assertNoNotification(1);
1191         }
1192         assertNoNotification(2);
1193     }
1194 
testForegroundService_notificationChannelDeletion()1195     public void testForegroundService_notificationChannelDeletion() throws Exception {
1196         NotificationManager noMan = mContext.getSystemService(NotificationManager.class);
1197 
1198         // Start service as foreground - it should show notification #1
1199         mExpectedServiceState = STATE_START_1;
1200         startForegroundService(COMMAND_START_FOREGROUND);
1201         waitForResultOrThrow(DELAY, "service to start first time");
1202         assertNotification(1, LocalForegroundService.getNotificationTitle(1), true);
1203 
1204         try {
1205             final String channel = LocalForegroundService.NOTIFICATION_CHANNEL_ID;
1206             noMan.deleteNotificationChannel(channel);
1207             fail("Deleting FGS notification channel did not throw");
1208         } catch (SecurityException se) {
1209             // Expected outcome, i.e. success case
1210         } catch (Exception e) {
1211             fail("Deleting FGS notification threw unexpected failure " + e);
1212         }
1213 
1214         mExpectedServiceState = STATE_DESTROY;
1215         mContext.stopService(mLocalForegroundService);
1216         waitForResultOrThrow(DELAY, "service to be destroyed");
1217 
1218     }
1219 
testForegroundService_deferredNotificationChannelDeletion()1220     public void testForegroundService_deferredNotificationChannelDeletion() throws Exception {
1221         NotificationManager noMan = mContext.getSystemService(NotificationManager.class);
1222 
1223         // Start service as foreground - it should show notification #1
1224         mExpectedServiceState = STATE_START_1;
1225         startForegroundService(COMMAND_START_FOREGROUND_DEFER_NOTIFICATION);
1226         waitForResultOrThrow(DELAY, "service to start first time");
1227         assertNoNotification(1);
1228 
1229         try {
1230             final String channel = LocalForegroundService.NOTIFICATION_CHANNEL_ID;
1231             noMan.deleteNotificationChannel(channel);
1232             fail("Deleting FGS deferred notification channel did not throw");
1233         } catch (SecurityException se) {
1234             // Expected outcome
1235         } catch (Exception e) {
1236             fail("Deleting deferred FGS notification threw unexpected failure " + e);
1237         }
1238 
1239         mExpectedServiceState = STATE_DESTROY;
1240         mContext.stopService(mLocalForegroundService);
1241         waitForResultOrThrow(DELAY, "service to be destroyed");
1242     }
1243 
testForegroundService_typeImmediateNotification()1244     public void testForegroundService_typeImmediateNotification() throws Exception {
1245         // expect that an FGS with phoneCall type has its notification displayed
1246         // immediately even without explicit request by the app
1247         mExpectedServiceState = STATE_START_1;
1248         startForegroundService(mLocalPhoneCallService,
1249                 COMMAND_START_FOREGROUND_DEFER_NOTIFICATION);
1250         waitForResultOrThrow(DELAY, "phoneCall service to start");
1251         assertNotification(1, LocalPhoneCallService.getNotificationTitle(1), true);
1252 
1253         mExpectedServiceState = STATE_DESTROY;
1254         mContext.stopService(mLocalPhoneCallService);
1255         waitForResultOrThrow(DELAY, "service to be destroyed");
1256     }
1257 
waitMillis(long timeMillis)1258     private void waitMillis(long timeMillis) {
1259         final long stopTime = SystemClock.uptimeMillis() + timeMillis;
1260         while (SystemClock.uptimeMillis() < stopTime) {
1261             try {
1262                 Thread.sleep(1000L);
1263             } catch (InterruptedException e) {
1264                 /* ignore */
1265             }
1266         }
1267     }
1268 
testForegroundService_deferredNotification()1269     public void testForegroundService_deferredNotification() throws Exception {
1270         mExpectedServiceState = STATE_START_1;
1271         startForegroundService(COMMAND_START_FOREGROUND_DEFER_NOTIFICATION);
1272         waitForResultOrThrow(DELAY, "service to start with deferred notification");
1273         assertNoNotification(1);
1274 
1275         // Wait ten seconds and verify that the notification is now visible
1276         waitMillis(10_000L);
1277         assertNotification(1, LocalForegroundService.getNotificationTitle(1), true);
1278 
1279         mExpectedServiceState = STATE_DESTROY;
1280         mContext.stopService(mLocalForegroundService);
1281         waitForResultOrThrow(DELAY, "service to be destroyed");
1282     }
1283 
testForegroundService_deferredExistingNotification()1284     public void testForegroundService_deferredExistingNotification() throws Exception {
1285         // First, post the notification outright as not-FGS-related
1286         final NotificationManager nm = getNotificationManager();
1287         final String channelId = LocalForegroundService.getNotificationChannelId();
1288         nm.createNotificationChannel(new NotificationChannel(channelId, channelId,
1289                 NotificationManager.IMPORTANCE_DEFAULT));
1290         Notification.Builder builder =
1291                 new Notification.Builder(mContext, channelId)
1292                         .setContentTitle("Before FGS")
1293                         .setSmallIcon(R.drawable.black);
1294         nm.notify(1, builder.build());
1295 
1296         mExpectedServiceState = STATE_START_1;
1297         startForegroundService(COMMAND_START_FOREGROUND_DEFER_NOTIFICATION);
1298         waitForResultOrThrow(DELAY, "service to start with existing notification");
1299 
1300         // Normally deferred but should display immediately because the notification
1301         // was already showing
1302         assertNotification(1, LocalForegroundService.getNotificationTitle(1), true);
1303 
1304         mExpectedServiceState = STATE_DESTROY;
1305         mContext.stopService(mLocalForegroundService);
1306         waitForResultOrThrow(DELAY, "service to be destroyed");
1307     }
1308 
testForegroundService_deferThenImmediateNotify()1309     public void testForegroundService_deferThenImmediateNotify() throws Exception {
1310         final String notificationTitle = "deferThenImmediateNotify";
1311 
1312         mExpectedServiceState = STATE_START_1;
1313         startForegroundService(COMMAND_START_FOREGROUND_DEFER_NOTIFICATION);
1314         waitForResultOrThrow(DELAY, "service to start with deferred notification");
1315         assertNoNotification(1);
1316 
1317         // Explicitly post a new Notification with the same id, still deferrable
1318         final NotificationManager nm = getNotificationManager();
1319         final String channelId = LocalForegroundService.getNotificationChannelId();
1320         nm.createNotificationChannel(new NotificationChannel(channelId, channelId,
1321                 NotificationManager.IMPORTANCE_DEFAULT));
1322         Notification.Builder builder =
1323                 new Notification.Builder(mContext, channelId)
1324                         .setContentTitle(notificationTitle)
1325                         .setSmallIcon(R.drawable.black)
1326                         .setForegroundServiceBehavior(Notification.FOREGROUND_SERVICE_IMMEDIATE);
1327         nm.notify(1, builder.build());
1328 
1329         // Verify that the notification is immediately shown with the new content
1330         assertNotification(1, notificationTitle, true);
1331 
1332         mExpectedServiceState = STATE_DESTROY;
1333         mContext.stopService(mLocalForegroundService);
1334         waitForResultOrThrow(DELAY, "service to be destroyed");
1335     }
1336 
testForegroundService_deferThenDeferrableNotify()1337     public void testForegroundService_deferThenDeferrableNotify() throws Exception {
1338         final String notificationTitle = "deferThenDeferrableNotify";
1339 
1340         mExpectedServiceState = STATE_START_1;
1341         startForegroundService(COMMAND_START_FOREGROUND_DEFER_NOTIFICATION);
1342         waitForResultOrThrow(DELAY, "service to start with deferred notification");
1343         // Pause a moment and ensure that the notification has still not appeared
1344         waitMillis(1000L);
1345         assertNoNotification(1);
1346 
1347         // Explicitly post a new Notification with the same id, still deferrable
1348         final NotificationManager nm = getNotificationManager();
1349         final String channelId = LocalForegroundService.getNotificationChannelId();
1350         nm.createNotificationChannel(new NotificationChannel(channelId, channelId,
1351                 NotificationManager.IMPORTANCE_DEFAULT));
1352         Notification.Builder builder =
1353                 new Notification.Builder(mContext, channelId)
1354                         .setContentTitle(notificationTitle)
1355                         .setSmallIcon(R.drawable.black)
1356                         .setForegroundServiceBehavior(Notification.FOREGROUND_SERVICE_DEFERRED);
1357         nm.notify(1, builder.build());
1358 
1359         // Normally would have displayed, but should only have been taken as the eventual
1360         // deferred notification.  Verify that it isn't shown yet, then re-verify after
1361         // the ten second deferral period that it's both visible and has the correct
1362         // (updated) title.
1363         assertNoNotification(1);
1364         waitMillis(10_000L);
1365         assertNotification(1, notificationTitle, true);
1366 
1367         mExpectedServiceState = STATE_DESTROY;
1368         mContext.stopService(mLocalForegroundService);
1369         waitForResultOrThrow(DELAY, "service to be destroyed");
1370     }
1371 
testForegroundService_deferThenKeepNotification()1372     public void testForegroundService_deferThenKeepNotification() throws Exception {
1373         // Start FGS with deferred notification; it should not display
1374         mExpectedServiceState = STATE_START_1;
1375         startForegroundService(COMMAND_START_FOREGROUND_DEFER_NOTIFICATION);
1376         waitForResultOrThrow(DELAY, "service to start first time");
1377         assertNoNotification(1);
1378 
1379         // Exit foreground but keep notification - it should display immediately
1380         mExpectedServiceState = STATE_START_2;
1381         startForegroundService(COMMAND_STOP_FOREGROUND_DONT_REMOVE_NOTIFICATION);
1382         waitForResultOrThrow(DELAY, "service to stop foreground");
1383         assertNotification(1, LocalForegroundService.getNotificationTitle(1), false);
1384 
1385         mExpectedServiceState = STATE_DESTROY;
1386         mContext.stopService(mLocalForegroundService);
1387         waitForResultOrThrow(DELAY, "service to be destroyed");
1388     }
1389 
1390     class TestSendCallback implements PendingIntent.OnFinished {
1391         public volatile int result = -1;
1392 
1393         @Override
onSendFinished(PendingIntent pendingIntent, Intent intent, int resultCode, String resultData, Bundle resultExtras)1394         public void onSendFinished(PendingIntent pendingIntent, Intent intent, int resultCode,
1395                 String resultData, Bundle resultExtras) {
1396             Log.i(TAG, "foreground service PendingIntent callback got " + resultCode);
1397             this.result = resultCode;
1398         }
1399     }
1400 
1401     @MediumTest
testForegroundService_pendingIntentForeground()1402     public void testForegroundService_pendingIntentForeground() throws Exception {
1403         boolean success = false;
1404 
1405         PendingIntent pi = PendingIntent.getForegroundService(mContext, 1,
1406                 foregroundServiceIntent(COMMAND_START_FOREGROUND),
1407                 PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE);
1408         TestSendCallback callback = new TestSendCallback();
1409 
1410         try {
1411             mExpectedServiceState = STATE_START_1;
1412             pi.send(5038, callback, null);
1413             waitForResultOrThrow(DELAY, "service to start first time");
1414             assertTrue(callback.result > -1);
1415 
1416             success = true;
1417         } finally {
1418             if (!success) {
1419                 mContext.stopService(mLocalForegroundService);
1420             }
1421         }
1422 
1423         mExpectedServiceState = STATE_DESTROY;
1424         mContext.stopService(mLocalForegroundService);
1425         waitForResultOrThrow(DELAY, "pendingintent service to be destroyed");
1426     }
1427 
1428     @MediumTest
testLocalBindAction()1429     public void testLocalBindAction() throws Exception {
1430         bindExpectResult(new Intent(
1431                 LocalService.SERVICE_LOCAL, null /*uri*/, mContext, LocalService.class));
1432     }
1433 
1434     @MediumTest
testLocalBindAutoClass()1435     public void testLocalBindAutoClass() throws Exception {
1436         bindAutoExpectResult(mLocalService);
1437     }
1438 
1439     @MediumTest
testLocalBindAutoAction()1440     public void testLocalBindAutoAction() throws Exception {
1441         bindAutoExpectResult(new Intent(
1442                 LocalService.SERVICE_LOCAL, null /*uri*/, mContext, LocalService.class));
1443     }
1444 
1445     @MediumTest
testLocalStartClassPermissions()1446     public void testLocalStartClassPermissions() throws Exception {
1447         startExpectResult(mLocalGrantedService);
1448         startExpectResult(mLocalDeniedService);
1449     }
1450 
1451     @MediumTest
testLocalStartActionPermissions()1452     public void testLocalStartActionPermissions() throws Exception {
1453         startExpectResult(mLocalService_ApplicationHasPermission);
1454         startExpectResult(mLocalService_ApplicationDoesNotHavePermission);
1455     }
1456 
1457     @MediumTest
testLocalBindClassPermissions()1458     public void testLocalBindClassPermissions() throws Exception {
1459         bindExpectResult(mLocalGrantedService);
1460         bindExpectResult(mLocalDeniedService);
1461     }
1462 
1463     @MediumTest
testLocalBindActionPermissions()1464     public void testLocalBindActionPermissions() throws Exception {
1465         bindExpectResult(mLocalService_ApplicationHasPermission);
1466         bindExpectResult(mLocalService_ApplicationDoesNotHavePermission);
1467     }
1468 
1469     @MediumTest
testLocalBindAutoClassPermissionGranted()1470     public void testLocalBindAutoClassPermissionGranted() throws Exception {
1471         bindAutoExpectResult(mLocalGrantedService);
1472     }
1473 
1474     @MediumTest
testLocalBindAutoActionPermissionGranted()1475     public void testLocalBindAutoActionPermissionGranted() throws Exception {
1476         bindAutoExpectResult(mLocalService_ApplicationHasPermission);
1477     }
1478 
1479     @MediumTest
testLocalUnbindTwice()1480     public void testLocalUnbindTwice() throws Exception {
1481         EmptyConnection conn = new EmptyConnection();
1482         mContext.bindService(
1483                 mLocalService_ApplicationHasPermission, conn, 0);
1484         mContext.unbindService(conn);
1485         try {
1486             mContext.unbindService(conn);
1487             fail("No exception thrown on the second unbind");
1488         } catch (IllegalArgumentException e) {
1489             // expected
1490         }
1491     }
1492 
1493     @MediumTest
testImplicitIntentFailsOnApiLevel21()1494     public void testImplicitIntentFailsOnApiLevel21() throws Exception {
1495         Intent intent = new Intent(LocalService.SERVICE_LOCAL);
1496         EmptyConnection conn = new EmptyConnection();
1497         try {
1498             mContext.bindService(intent, conn, 0);
1499             mContext.unbindService(conn);
1500             fail("Implicit intents should be disallowed for apps targeting API 21+");
1501         } catch (IllegalArgumentException e) {
1502             // expected
1503         }
1504     }
1505 
1506     /**
1507      * Verify that when the requested service's onBind() returns null,
1508      * the connection's onNullBinding() method is invoked.
1509      */
1510     @MediumTest
testNullServiceBinder()1511     public void testNullServiceBinder() throws Exception {
1512         Intent intent = new Intent(mContext, NullService.class);
1513         intent.setAction("testNullServiceBinder");
1514         NullServiceConnection conn1 = new NullServiceConnection();
1515         NullServiceConnection conn2 = new NullServiceConnection();
1516         try {
1517             assertTrue(mContext.bindService(intent, conn1, Context.BIND_AUTO_CREATE));
1518             conn1.waitForNullBinding(DELAY);
1519             assertTrue(conn1.nullBindingReceived());
1520 
1521             assertTrue(mContext.bindService(intent, conn2, Context.BIND_AUTO_CREATE));
1522             conn2.waitForNullBinding(DELAY);
1523             assertTrue(conn2.nullBindingReceived());
1524         } finally {
1525             mContext.unbindService(conn1);
1526             mContext.unbindService(conn2);
1527         }
1528     }
1529 
1530     /**
1531      * Verify that we can't use bindIsolatedService() on a non-isolated service.
1532      */
1533     @MediumTest
testFailBindNonIsolatedService()1534     public void testFailBindNonIsolatedService() throws Exception {
1535         EmptyConnection conn = new EmptyConnection();
1536         try {
1537             mContext.bindIsolatedService(mLocalService, 0, "isolated", mContextMainExecutor, conn);
1538             mContext.unbindService(conn);
1539             fail("Didn't get IllegalArgumentException");
1540         } catch (IllegalArgumentException e) {
1541             // This is expected.
1542         }
1543     }
1544 
1545     /**
1546      * Verify that certain characters are prohibited in instanceName.
1547      */
testFailBindIsoaltedServiceWithInvalidInstanceName()1548     public void testFailBindIsoaltedServiceWithInvalidInstanceName() throws Exception {
1549         String[] badNames = {
1550             "t\rest",
1551             "test\n",
1552             "test-three",
1553             "test four",
1554             "escape\u00a9seq",
1555             "\u0164est",
1556         };
1557         for (String instanceName : badNames) {
1558             EmptyConnection conn = new EmptyConnection();
1559             try {
1560                 mContext.bindIsolatedService(mIsolatedService, Context.BIND_AUTO_CREATE,
1561                         instanceName, mContextMainExecutor, conn);
1562                 mContext.unbindService(conn);
1563                 fail("Didn't get IllegalArgumentException: " + instanceName);
1564             } catch (IllegalArgumentException e) {
1565                 // This is expected.
1566             }
1567         }
1568     }
1569 
1570     /**
1571      * Verify that bindIsolatedService() correctly makes different instances when given
1572      * different instance names.
1573      */
1574     @MediumTest
testBindIsolatedServiceInstances()1575     public void testBindIsolatedServiceInstances() throws Exception {
1576         IsolatedConnection conn1a = null;
1577         IsolatedConnection conn1b = null;
1578         IsolatedConnection conn2 = null;
1579         try {
1580             conn1a = new IsolatedConnection();
1581             mContext.bindIsolatedService(
1582                     mIsolatedService, Context.BIND_AUTO_CREATE, "1", mContextMainExecutor, conn1a);
1583             conn1b = new IsolatedConnection();
1584             mContext.bindIsolatedService(
1585                     mIsolatedService, Context.BIND_AUTO_CREATE, "1", mContextMainExecutor, conn1b);
1586             conn2 = new IsolatedConnection();
1587             mContext.bindIsolatedService(
1588                     mIsolatedService, Context.BIND_AUTO_CREATE, "2", mContextMainExecutor, conn2);
1589 
1590             conn1a.waitForService(DELAY);
1591             conn1b.waitForService(DELAY);
1592             conn2.waitForService(DELAY);
1593 
1594             if (conn1a.getPid() != conn1b.getPid()) {
1595                 fail("Connections to same service name in different pids");
1596             }
1597             if (conn1a.getPid() == conn2.getPid()) {
1598                 fail("Connections to different service names in same pids");
1599             }
1600 
1601             conn1a.setValue(1);
1602             assertEquals(1, conn1a.getValue());
1603             assertEquals(1, conn1b.getValue());
1604 
1605             conn2.setValue(2);
1606             assertEquals(1, conn1a.getValue());
1607             assertEquals(1, conn1b.getValue());
1608             assertEquals(2, conn2.getValue());
1609 
1610             conn1b.setValue(3);
1611             assertEquals(3, conn1a.getValue());
1612             assertEquals(3, conn1b.getValue());
1613             assertEquals(2, conn2.getValue());
1614         } finally {
1615             if (conn2 != null) {
1616                 mContext.unbindService(conn2);
1617             }
1618             if (conn1b != null) {
1619                 mContext.unbindService(conn1b);
1620             }
1621             if (conn1a != null) {
1622                 mContext.unbindService(conn1a);
1623             }
1624         }
1625     }
1626 
1627     @MediumTest
testOnCreateCalledOnce_bindService()1628     public void testOnCreateCalledOnce_bindService() throws Exception {
1629         IsolatedConnection conn = null;
1630 
1631         try {
1632             conn = new IsolatedConnection();
1633             mContext.bindService(
1634                     mDelayedService, Context.BIND_AUTO_CREATE, mContextMainExecutor, conn);
1635 
1636             // Wait for app to be executing bindApplication
1637             SystemClock.sleep(1000);
1638 
1639             mContext.bindService(
1640                     mDelayedService, Context.BIND_AUTO_CREATE, mContextMainExecutor, conn);
1641 
1642             conn.waitForService(DELAY);
1643 
1644             assertEquals(1, conn.getOnCreateCalledCount());
1645         } finally {
1646             if (conn != null) {
1647                 mContext.unbindService(conn);
1648             }
1649         }
1650     }
1651 
testBindIsolatedServiceOnBackgroundThread()1652     public void testBindIsolatedServiceOnBackgroundThread() throws Exception {
1653         setupBackgroundThread();
1654         IsolatedConnection conn = new IsolatedConnection();
1655         mContext.bindIsolatedService(mIsolatedService, Context.BIND_AUTO_CREATE,
1656             "background_instance", mBackgroundThreadExecutor, conn);
1657         conn.waitForService(DELAY);
1658         assertEquals(mBackgroundThread, conn.getOnServiceConnectedThread());
1659         mContext.unbindService(conn);
1660     }
1661 
1662     static final int BINDING_WEAK = 0;
1663     static final int BINDING_STRONG = 1;
1664     static final int BINDING_ANY = -1;
1665 
1666     final class IsolatedConnectionInfo {
1667         final int mStrong;
1668         final String mInstanceName;
1669         final String mLabel;
1670         int mGroup;
1671         int mImportance;
1672         IsolatedConnection mConnection;
1673 
IsolatedConnectionInfo(int group, int importance, int strong)1674         IsolatedConnectionInfo(int group, int importance, int strong) {
1675             mGroup = group;
1676             mImportance = importance;
1677             mStrong = strong;
1678             mInstanceName = group + "_" + importance;
1679             StringBuilder b = new StringBuilder(mInstanceName);
1680             b.append('_');
1681             if (strong == BINDING_WEAK) {
1682                 b.append('W');
1683             } else if (strong == BINDING_STRONG) {
1684                 b.append('S');
1685             } else {
1686                 b.append(strong);
1687             }
1688             mLabel = b.toString();
1689         }
1690 
setGroup(int group)1691         void setGroup(int group) {
1692             mGroup = group;
1693         }
1694 
setImportance(int importance)1695         void setImportance(int importance) {
1696             mImportance = importance;
1697         }
1698 
match(int group, int strong)1699         boolean match(int group, int strong) {
1700             return (group < 0 || mGroup == group)
1701                     && (strong == BINDING_ANY || mStrong == strong);
1702         }
1703 
bind(Context context)1704         boolean bind(Context context) {
1705             if (mConnection != null) {
1706                 return true;
1707             }
1708             Log.i("XXXXXXX", "Binding " + mLabel + ": conn=" + mConnection
1709                     + " context=" + context);
1710             mConnection = new IsolatedConnection();
1711             boolean result = context.bindIsolatedService(
1712                     mIsolatedService,
1713                     Context.BIND_AUTO_CREATE | Context.BIND_DEBUG_UNBIND
1714                             | (mStrong == BINDING_STRONG ? 0 : Context.BIND_ALLOW_OOM_MANAGEMENT),
1715                     mInstanceName, mContextMainExecutor, mConnection);
1716             if (!result) {
1717                 mConnection = null;
1718             }
1719             return result;
1720         }
1721 
getConnection()1722         IsolatedConnection getConnection() {
1723             return mConnection;
1724         }
1725 
unbind(Context context)1726         void unbind(Context context) {
1727             if (mConnection != null) {
1728                 Log.i("XXXXXXX", "Unbinding " + mLabel + ": conn=" + mConnection
1729                         + " context=" + context);
1730                 context.unbindService(mConnection);
1731                 mConnection = null;
1732             }
1733         }
1734     }
1735 
1736     final class LruOrderItem {
1737         static final int FLAG_SKIP_UNKNOWN = 1<<0;
1738 
1739         final IsolatedConnectionInfo mInfo;
1740         final int mUid;
1741         final int mFlags;
1742 
LruOrderItem(IsolatedConnectionInfo info, int flags)1743         LruOrderItem(IsolatedConnectionInfo info, int flags) {
1744             mInfo = info;
1745             mUid = -1;
1746             mFlags = flags;
1747         }
1748 
LruOrderItem(int uid, int flags)1749         LruOrderItem(int uid, int flags) {
1750             mInfo = null;
1751             mUid = uid;
1752             mFlags = flags;
1753         }
1754 
getInfo()1755         IsolatedConnectionInfo getInfo() {
1756             return mInfo;
1757         }
1758 
getUid()1759         int getUid() {
1760             return mInfo != null ? mInfo.getConnection().getUid() : mUid;
1761         }
1762 
getUserId()1763         int getUserId() {
1764             return UserHandle.getUserHandleForUid(getUid()).getIdentifier();
1765         }
1766 
getAppId()1767         int getAppId() {
1768             return UserHandle.getAppId(getUid());
1769         }
1770 
isEquivalentTo(ProcessRecordProto proc)1771         boolean isEquivalentTo(ProcessRecordProto proc) {
1772             int procAppId = proc.isolatedAppId != 0 ? proc.isolatedAppId : UserHandle.getAppId(
1773                     proc.uid);
1774 
1775             // Compare appid and userid separately because UserHandle.getUid is @hide.
1776             return procAppId == getAppId() && proc.userId == getUserId();
1777         }
1778 
getFlags()1779         int getFlags() {
1780             return mFlags;
1781         }
1782     }
1783 
doBind(Context context, IsolatedConnectionInfo[] connections, int group, int strong)1784     private void doBind(Context context, IsolatedConnectionInfo[] connections, int group,
1785             int strong) {
1786         for (IsolatedConnectionInfo ci : connections) {
1787             if (ci.match(group, strong)) {
1788                 ci.bind(context);
1789             }
1790         }
1791     }
1792 
doBind(Context context, IsolatedConnectionInfo[] connections, int[] selected)1793     private void doBind(Context context, IsolatedConnectionInfo[] connections, int[] selected) {
1794         for (int i : selected) {
1795             boolean result = connections[i].bind(context);
1796             if (!result) {
1797                 fail("Unable to bind connection " + connections[i].mLabel);
1798             }
1799         }
1800     }
1801 
doWaitForService(IsolatedConnectionInfo[] connections, int group, int strong)1802     private void doWaitForService(IsolatedConnectionInfo[] connections, int group,
1803             int strong) {
1804         for (IsolatedConnectionInfo ci : connections) {
1805             if (ci.match(group, strong)) {
1806                 ci.mConnection.waitForService(DELAY);
1807             }
1808         }
1809     }
1810 
doUpdateServiceGroup(Context context, IsolatedConnectionInfo[] connections, int group, int strong)1811     private void doUpdateServiceGroup(Context context, IsolatedConnectionInfo[] connections,
1812             int group, int strong) {
1813         for (IsolatedConnectionInfo ci : connections) {
1814             if (ci.match(group, strong)) {
1815                 context.updateServiceGroup(ci.mConnection, ci.mGroup, ci.mImportance);
1816             }
1817         }
1818     }
1819 
doUnbind(Context context, IsolatedConnectionInfo[] connections, int group, int strong)1820     private void doUnbind(Context context, IsolatedConnectionInfo[] connections, int group,
1821             int strong) {
1822         for (IsolatedConnectionInfo ci : connections) {
1823             if (ci.match(group, strong)) {
1824                 ci.unbind(context);
1825             }
1826         }
1827     }
1828 
doUnbind(Context context, IsolatedConnectionInfo[] connections, int[] selected)1829     private void doUnbind(Context context, IsolatedConnectionInfo[] connections, int[] selected) {
1830         for (int i : selected) {
1831             connections[i].unbind(context);
1832         }
1833     }
1834 
getLruProcesses()1835     List<ProcessRecordProto> getLruProcesses() {
1836         ActivityManagerServiceDumpProcessesProto dump = getActivityManagerProcesses();
1837         SparseArray<ProcessRecordProto> procs = new SparseArray<>();
1838         ProcessRecordProto[] procsList = dump.procs;
1839         for (ProcessRecordProto proc : procsList) {
1840             procs.put(proc.lruIndex, proc);
1841         }
1842         ArrayList<ProcessRecordProto> lruProcs = new ArrayList<>();
1843         for (int i = 0; i < procs.size(); i++) {
1844             lruProcs.add(procs.valueAt(i));
1845         }
1846         return lruProcs;
1847     }
1848 
printProc(int i, ProcessRecordProto proc)1849     String printProc(int i, ProcessRecordProto proc) {
1850         return "#" + i + ": " + proc.processName
1851                 + " pid=" + proc.pid + " uid=" + proc.uid
1852                 + (proc.isolatedAppId != 0 ? " isolated=" + proc.isolatedAppId : "");
1853     }
1854 
logProc(int i, ProcessRecordProto proc)1855     private void logProc(int i, ProcessRecordProto proc) {
1856         Log.i("XXXXXXXX", printProc(i, proc));
1857     }
1858 
verifyLruOrder(LruOrderItem[] orderItems)1859     private void verifyLruOrder(LruOrderItem[] orderItems) {
1860         List<ProcessRecordProto> procs = getLruProcesses();
1861         Log.i("XXXXXXXX", "Processes:");
1862         int orderI = 0;
1863         for (int i = procs.size() - 1; i >= 0; i--) {
1864             ProcessRecordProto proc = procs.get(i);
1865             logProc(i, proc);
1866             final LruOrderItem lru = orderItems[orderI];
1867             Log.i("XXXXXXXX", "Expecting uid: " + lru.getUid());
1868             if (!lru.isEquivalentTo(proc)) {
1869                 if ((lru.getFlags() & LruOrderItem.FLAG_SKIP_UNKNOWN) != 0) {
1870                     while (i > 0) {
1871                         i--;
1872                         proc = procs.get(i);
1873                         logProc(i, proc);
1874                         if (lru.isEquivalentTo(proc)) {
1875                             break;
1876                         }
1877                     }
1878                 }
1879                 if (!lru.isEquivalentTo(proc)) {
1880                     if ((lru.getFlags() & LruOrderItem.FLAG_SKIP_UNKNOWN) != 0) {
1881                         fail("Didn't find expected LRU proc uid=" + lru.getUid());
1882                     }
1883                     fail("Expected proc uid=" + lru.getUid() + " at found proc "
1884                             + printProc(i, proc));
1885                 }
1886             }
1887             orderI++;
1888             if (orderI >= orderItems.length) {
1889                 return;
1890             }
1891         }
1892     }
1893 
1894     @MediumTest
testAppZygotePreload()1895     public void testAppZygotePreload() throws Exception {
1896         IsolatedConnection conn = new IsolatedConnection();
1897         try {
1898             mContext.bindIsolatedService(
1899                     mIsolatedService, Context.BIND_AUTO_CREATE, "1", mContextMainExecutor, conn);
1900 
1901             conn.waitForService(DELAY);
1902 
1903             // Verify application preload was done
1904             assertTrue(conn.zygotePreloadCalled());
1905         } finally {
1906             if (conn != null) {
1907                 mContext.unbindService(conn);
1908             }
1909         }
1910     }
1911 
1912     @MediumTest
testAppZygoteServices()1913     public void testAppZygoteServices() throws Exception {
1914         IsolatedConnection conn1a = null;
1915         IsolatedConnection conn1b = null;
1916         IsolatedConnection conn2 = null;
1917         int appZygotePid;
1918         try {
1919             conn1a = new IsolatedConnection();
1920             mContext.bindIsolatedService(
1921                     mIsolatedService, Context.BIND_AUTO_CREATE, "1", mContextMainExecutor, conn1a);
1922             conn1b = new IsolatedConnection();
1923             mContext.bindIsolatedService(
1924                     mIsolatedService, Context.BIND_AUTO_CREATE, "1", mContextMainExecutor, conn1b);
1925             conn2 = new IsolatedConnection();
1926             mContext.bindIsolatedService(
1927                     mIsolatedService, Context.BIND_AUTO_CREATE, "2", mContextMainExecutor, conn2);
1928 
1929             conn1a.waitForService(DELAY);
1930             conn1b.waitForService(DELAY);
1931             conn2.waitForService(DELAY);
1932 
1933             // Get PPID of each service, and verify they're identical
1934             int ppid1a = conn1a.getPpid();
1935             int ppid1b = conn1b.getPpid();
1936             int ppid2 = conn2.getPpid();
1937 
1938             assertEquals(ppid1a, ppid1b);
1939             assertEquals(ppid1b, ppid2);
1940             // Find the app zygote process hosting these
1941             String result = SystemUtil.runShellCommand(InstrumentationRegistry.getInstrumentation(),
1942                 "ps -p " + Integer.toString(ppid1a) + " -o NAME=");
1943             result = result.replaceAll("\\s+", "");
1944             assertEquals(result, APP_ZYGOTE_PROCESS_NAME);
1945             appZygotePid = ppid1a;
1946         } finally {
1947             if (conn2 != null) {
1948                 mContext.unbindService(conn2);
1949             }
1950             if (conn1b != null) {
1951                 mContext.unbindService(conn1b);
1952             }
1953             if (conn1a != null) {
1954                 mContext.unbindService(conn1a);
1955             }
1956         }
1957         // Sleep for 2 seconds and bind a service again, see it uses the same Zygote
1958         try {
1959             conn1a = new IsolatedConnection();
1960             mContext.bindIsolatedService(
1961                     mIsolatedService, Context.BIND_AUTO_CREATE, "1", mContextMainExecutor, conn1a);
1962 
1963             conn1a.waitForService(DELAY);
1964 
1965             int ppid1a = conn1a.getPpid();
1966             assertEquals(appZygotePid, ppid1a);
1967         } finally {
1968             if (conn1a != null) {
1969                 mContext.unbindService(conn1a);
1970             }
1971         }
1972         // Sleep for 10 seconds, verify the app_zygote is gone
1973         Thread.sleep(10000);
1974         String result = SystemUtil.runShellCommand(InstrumentationRegistry.getInstrumentation(),
1975             "ps -p " + Integer.toString(appZygotePid) + " -o NAME=");
1976         result = result.replaceAll("\\s+", "");
1977         assertEquals("", result);
1978     }
1979 
1980     /**
1981      * Test that the system properly orders processes bound by an activity within the
1982      * LRU list.
1983      */
1984     // TODO(b/131059432): Re-enable the test after that bug is fixed.
1985     @FlakyTest
1986     @MediumTest
testActivityServiceBindingLru()1987     public void testActivityServiceBindingLru() throws Exception {
1988         // Bring up the activity we will hang services off of.
1989         runLaunchpad(LaunchpadActivity.ACTIVITY_PREPARE);
1990 
1991         final Activity a = getRunningActivity();
1992 
1993         final int CONN_1_1_W = 0;
1994         final int CONN_1_1_S = 1;
1995         final int CONN_1_2_W = 2;
1996         final int CONN_1_2_S = 3;
1997         final int CONN_2_1_W = 4;
1998         final int CONN_2_1_S = 5;
1999         final int CONN_2_2_W = 6;
2000         final int CONN_2_2_S = 7;
2001         final int CONN_2_3_W = 8;
2002         final int CONN_2_3_S = 9;
2003 
2004         // We are going to have both weak and strong references to services, so we can allow
2005         // some to go down in the LRU list.
2006         final IsolatedConnectionInfo[] connections = new IsolatedConnectionInfo[] {
2007                 new IsolatedConnectionInfo(1, 1, BINDING_WEAK),
2008                 new IsolatedConnectionInfo(1, 1, BINDING_STRONG),
2009                 new IsolatedConnectionInfo(1, 2, BINDING_WEAK),
2010                 new IsolatedConnectionInfo(1, 2, BINDING_STRONG),
2011                 new IsolatedConnectionInfo(2, 1, BINDING_WEAK),
2012                 new IsolatedConnectionInfo(2, 1, BINDING_STRONG),
2013                 new IsolatedConnectionInfo(2, 2, BINDING_WEAK),
2014                 new IsolatedConnectionInfo(2, 2, BINDING_STRONG),
2015                 new IsolatedConnectionInfo(2, 3, BINDING_WEAK),
2016                 new IsolatedConnectionInfo(2, 3, BINDING_STRONG),
2017         };
2018 
2019         final int[] REV_GROUP_1_STRONG = new int[] {
2020                 CONN_1_2_S, CONN_1_1_S
2021         };
2022 
2023         final int[] REV_GROUP_2_STRONG = new int[] {
2024                 CONN_2_3_S, CONN_2_2_S, CONN_2_1_S
2025         };
2026 
2027         final int[] MIXED_GROUP_3_STRONG = new int[] {
2028                 CONN_2_3_S, CONN_1_1_S, CONN_2_1_S, CONN_2_2_S
2029         };
2030 
2031         boolean passed = false;
2032 
2033         try {
2034             // Start the group 1 processes as weak.
2035             doBind(a, connections, 1, BINDING_WEAK);
2036             doUpdateServiceGroup(a, connections, 1, BINDING_WEAK);
2037 
2038             // Wait for them to come up.
2039             doWaitForService(connections, 1, BINDING_WEAK);
2040 
2041             // Now fully bind to the services.
2042             doBind(a, connections, 1, BINDING_STRONG);
2043             doWaitForService(connections, 1, BINDING_STRONG);
2044 
2045             verifyLruOrder(new LruOrderItem[] {
2046                     new LruOrderItem(Process.myUid(), 0),
2047                     new LruOrderItem(connections[CONN_1_1_W], 0),
2048                     new LruOrderItem(connections[CONN_1_2_W], 0),
2049             });
2050 
2051             // Now remove the full binding, leaving only the weak.
2052             doUnbind(a, connections, 1, BINDING_STRONG);
2053 
2054             // Start the group 2 processes as weak.
2055             doBind(a, connections, 2, BINDING_WEAK);
2056 
2057             // Wait for them to come up.
2058             doWaitForService(connections, 2, BINDING_WEAK);
2059 
2060             // Set the group and index.  In this case we do it after we know the process
2061             // is started, to make sure setting it directly works.
2062             doUpdateServiceGroup(a, connections, 2, BINDING_WEAK);
2063 
2064             // Now fully bind to group 2
2065             doBind(a, connections, REV_GROUP_2_STRONG);
2066 
2067             verifyLruOrder(new LruOrderItem[] {
2068                     new LruOrderItem(Process.myUid(), 0),
2069                     new LruOrderItem(connections[CONN_2_1_W], 0),
2070                     new LruOrderItem(connections[CONN_2_2_W], 0),
2071                     new LruOrderItem(connections[CONN_2_3_W], 0),
2072                     new LruOrderItem(connections[CONN_1_1_W], LruOrderItem.FLAG_SKIP_UNKNOWN),
2073                     new LruOrderItem(connections[CONN_1_2_W], 0),
2074             });
2075 
2076             // Bring group 1 back to the foreground, but in the opposite order.
2077             doBind(a, connections, REV_GROUP_1_STRONG);
2078 
2079             verifyLruOrder(new LruOrderItem[] {
2080                     new LruOrderItem(Process.myUid(), 0),
2081                     new LruOrderItem(connections[CONN_1_1_W], 0),
2082                     new LruOrderItem(connections[CONN_1_2_W], 0),
2083                     new LruOrderItem(connections[CONN_2_1_W], LruOrderItem.FLAG_SKIP_UNKNOWN),
2084                     new LruOrderItem(connections[CONN_2_2_W], 0),
2085                     new LruOrderItem(connections[CONN_2_3_W], 0),
2086             });
2087 
2088             // Now remove all full bindings, keeping only weak.
2089             doUnbind(a, connections, 1, BINDING_STRONG);
2090             doUnbind(a, connections, 2, BINDING_STRONG);
2091 
2092             // Change the grouping and importance to make sure that gets reflected.
2093             connections[CONN_1_1_W].setGroup(3);
2094             connections[CONN_1_1_W].setImportance(1);
2095             connections[CONN_2_1_W].setGroup(3);
2096             connections[CONN_2_1_W].setImportance(2);
2097             connections[CONN_2_2_W].setGroup(3);
2098             connections[CONN_2_2_W].setImportance(3);
2099             connections[CONN_2_3_W].setGroup(3);
2100             connections[CONN_2_3_W].setImportance(4);
2101 
2102             doUpdateServiceGroup(a, connections, 3, BINDING_WEAK);
2103 
2104             // Now bind them back up in an interesting order.
2105             doBind(a, connections, MIXED_GROUP_3_STRONG);
2106 
2107             verifyLruOrder(new LruOrderItem[] {
2108                     new LruOrderItem(Process.myUid(), 0),
2109                     new LruOrderItem(connections[CONN_1_1_W], 0),
2110                     new LruOrderItem(connections[CONN_2_1_W], 0),
2111                     new LruOrderItem(connections[CONN_2_2_W], 0),
2112                     new LruOrderItem(connections[CONN_2_3_W], 0),
2113                     new LruOrderItem(connections[CONN_1_2_W], LruOrderItem.FLAG_SKIP_UNKNOWN),
2114             });
2115 
2116             passed = true;
2117 
2118         } finally {
2119             if (!passed) {
2120                 List<ProcessRecordProto> procs = getLruProcesses();
2121                 Log.i("XXXXXXXX", "Processes:");
2122                 for (int i = procs.size() - 1; i >= 0; i--) {
2123                     ProcessRecordProto proc = procs.get(i);
2124                     logProc(i, proc);
2125                 }
2126             }
2127             doUnbind(a, connections, -1, BINDING_ANY);
2128         }
2129     }
2130 
2131     /**
2132      * Test per process's max outgoing bindService() service connections.
2133      * @throws Exception
2134      */
testMaxServiceConnections()2135     public void testMaxServiceConnections() throws Exception {
2136         final ArrayList<LatchedConnection> connections = new ArrayList<>();
2137         final int max = 1000;
2138         final int extra = 10;
2139         DeviceConfigStateHelper helper = new DeviceConfigStateHelper("activity_manager");
2140         try {
2141             helper.set(KEY_MAX_SERVICE_CONNECTIONS_PER_PROCESS, Integer.toString(max));
2142             // bindService() adds max number of ServiceConnections.
2143             for (int i = 0; i < max; ++i) {
2144                 final CountDownLatch latch = new CountDownLatch(1);
2145                 final LatchedConnection connection = new LatchedConnection(latch);
2146                 connections.add(connection);
2147                 assertTrue(mContext.bindService(mLocalService, connection,
2148                         Context.BIND_AUTO_CREATE));
2149                 assertTrue(latch.await(5, TimeUnit.SECONDS));
2150             }
2151             // bindService() adds "extra" number of ServiceConnections, it should fail.
2152             for (int i = 0; i < extra; ++i) {
2153                 final CountDownLatch latch = new CountDownLatch(1);
2154                 final LatchedConnection connection = new LatchedConnection(latch);
2155                 assertFalse(mContext.bindService(mLocalService, connection,
2156                         Context.BIND_AUTO_CREATE));
2157             }
2158             // unbindService removes max/4 number of ServiceConnections.
2159             for (int i = 0; i < max / 4; ++i) {
2160                 final LatchedConnection connection = connections.remove(0);
2161                 mContext.unbindService(connection);
2162             }
2163             // bindService adds max/4 number of ServiceConnections.
2164             for (int i = 0; i < max / 4; ++i) {
2165                 final CountDownLatch latch = new CountDownLatch(1);
2166                 final LatchedConnection connection = new LatchedConnection(latch);
2167                 connections.add(connection);
2168                 assertTrue(mContext.bindService(mLocalService, connection,
2169                         Context.BIND_AUTO_CREATE));
2170                 assertTrue(latch.await(5, TimeUnit.SECONDS));
2171             }
2172         } finally {
2173             helper.restoreOriginalValues();
2174             for (ServiceConnection connection : connections) {
2175                 mContext.unbindService(connection);
2176             }
2177         }
2178     }
2179 
2180 
2181     /**
2182      * Test bindService() flags can be 64 bits long.
2183      * @throws Exception
2184      */
testBindServiceLongFlags()2185     public void testBindServiceLongFlags() throws Exception {
2186         long flags = Context.BIND_AUTO_CREATE;
2187         testBindServiceFlagsLongInternal(flags);
2188         flags = 0x0000_1111_0000_0000L | Context.BIND_AUTO_CREATE;
2189         testBindServiceFlagsLongInternal(flags);
2190         flags = 0x0fff_ffff_0000_0000L | Context.BIND_AUTO_CREATE;
2191         testBindServiceFlagsLongInternal(flags);
2192     }
2193 
testBindServiceFlagsLongInternal(long flags)2194     private void testBindServiceFlagsLongInternal(long flags) throws Exception {
2195         final CountDownLatch latch = new CountDownLatch(1);
2196         final LatchedConnection connection = new LatchedConnection(latch);
2197         try {
2198             assertTrue(mContext.bindService(mLocalService, connection,
2199                     Context.BindServiceFlags.of(flags)));
2200             assertTrue(latch.await(5, TimeUnit.SECONDS));
2201             final String dumpCommand = "dumpsys activity services " + "android.app.stubs"
2202                     + "/android.app.stubs.LocalService";
2203             String[] dumpLines = CtsAppTestUtils.executeShellCmd(
2204                     InstrumentationRegistry.getInstrumentation(), dumpCommand).split("\n");
2205             assertNotNull(CtsAppTestUtils.findLine(dumpLines,
2206                     "flags=0x" + Long.toHexString(flags)));
2207         } finally {
2208             mContext.unbindService(connection);
2209         }
2210     }
2211 }
2212