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