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