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         // Pause a moment and ensure that the notification has still not appeared
1273         waitMillis(1000L);
1274         assertNoNotification(1);
1275 
1276         // Explicitly post a new Notification with the same id, still deferrable
1277         final NotificationManager nm = getNotificationManager();
1278         final String channelId = LocalForegroundService.getNotificationChannelId();
1279         nm.createNotificationChannel(new NotificationChannel(channelId, channelId,
1280                 NotificationManager.IMPORTANCE_DEFAULT));
1281         Notification.Builder builder =
1282                 new Notification.Builder(mContext, channelId)
1283                         .setContentTitle(notificationTitle)
1284                         .setSmallIcon(R.drawable.black)
1285                         .setForegroundServiceBehavior(Notification.FOREGROUND_SERVICE_DEFERRED);
1286         nm.notify(1, builder.build());
1287 
1288         // Normally would have displayed, but should only have been taken as the eventual
1289         // deferred notification.  Verify that it isn't shown yet, then re-verify after
1290         // the ten second deferral period that it's both visible and has the correct
1291         // (updated) title.
1292         assertNoNotification(1);
1293         waitMillis(10_000L);
1294         assertNotification(1, notificationTitle);
1295 
1296         mExpectedServiceState = STATE_DESTROY;
1297         mContext.stopService(mLocalForegroundService);
1298         waitForResultOrThrow(DELAY, "service to be destroyed");
1299     }
1300 
testForegroundService_deferThenKeepNotification()1301     public void testForegroundService_deferThenKeepNotification() throws Exception {
1302         // Start FGS with deferred notification; it should not display
1303         mExpectedServiceState = STATE_START_1;
1304         startForegroundService(COMMAND_START_FOREGROUND_DEFER_NOTIFICATION);
1305         waitForResultOrThrow(DELAY, "service to start first time");
1306         assertNoNotification(1);
1307 
1308         // Exit foreground but keep notification - it should display immediately
1309         mExpectedServiceState = STATE_START_2;
1310         startForegroundService(COMMAND_STOP_FOREGROUND_DONT_REMOVE_NOTIFICATION);
1311         waitForResultOrThrow(DELAY, "service to stop foreground");
1312         assertNotification(1, LocalForegroundService.getNotificationTitle(1));
1313 
1314         mExpectedServiceState = STATE_DESTROY;
1315         mContext.stopService(mLocalForegroundService);
1316         waitForResultOrThrow(DELAY, "service to be destroyed");
1317     }
1318 
1319     class TestSendCallback implements PendingIntent.OnFinished {
1320         public volatile int result = -1;
1321 
1322         @Override
onSendFinished(PendingIntent pendingIntent, Intent intent, int resultCode, String resultData, Bundle resultExtras)1323         public void onSendFinished(PendingIntent pendingIntent, Intent intent, int resultCode,
1324                 String resultData, Bundle resultExtras) {
1325             Log.i(TAG, "foreground service PendingIntent callback got " + resultCode);
1326             this.result = resultCode;
1327         }
1328     }
1329 
1330     @MediumTest
testForegroundService_pendingIntentForeground()1331     public void testForegroundService_pendingIntentForeground() throws Exception {
1332         boolean success = false;
1333 
1334         PendingIntent pi = PendingIntent.getForegroundService(mContext, 1,
1335                 foregroundServiceIntent(COMMAND_START_FOREGROUND),
1336                 PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE);
1337         TestSendCallback callback = new TestSendCallback();
1338 
1339         try {
1340             mExpectedServiceState = STATE_START_1;
1341             pi.send(5038, callback, null);
1342             waitForResultOrThrow(DELAY, "service to start first time");
1343             assertTrue(callback.result > -1);
1344 
1345             success = true;
1346         } finally {
1347             if (!success) {
1348                 mContext.stopService(mLocalForegroundService);
1349             }
1350         }
1351 
1352         mExpectedServiceState = STATE_DESTROY;
1353         mContext.stopService(mLocalForegroundService);
1354         waitForResultOrThrow(DELAY, "pendingintent service to be destroyed");
1355     }
1356 
1357     @MediumTest
testLocalBindAction()1358     public void testLocalBindAction() throws Exception {
1359         bindExpectResult(new Intent(
1360                 LocalService.SERVICE_LOCAL, null /*uri*/, mContext, LocalService.class));
1361     }
1362 
1363     @MediumTest
testLocalBindAutoClass()1364     public void testLocalBindAutoClass() throws Exception {
1365         bindAutoExpectResult(mLocalService);
1366     }
1367 
1368     @MediumTest
testLocalBindAutoAction()1369     public void testLocalBindAutoAction() throws Exception {
1370         bindAutoExpectResult(new Intent(
1371                 LocalService.SERVICE_LOCAL, null /*uri*/, mContext, LocalService.class));
1372     }
1373 
1374     @MediumTest
testLocalStartClassPermissions()1375     public void testLocalStartClassPermissions() throws Exception {
1376         startExpectResult(mLocalGrantedService);
1377         startExpectResult(mLocalDeniedService);
1378     }
1379 
1380     @MediumTest
testLocalStartActionPermissions()1381     public void testLocalStartActionPermissions() throws Exception {
1382         startExpectResult(mLocalService_ApplicationHasPermission);
1383         startExpectResult(mLocalService_ApplicationDoesNotHavePermission);
1384     }
1385 
1386     @MediumTest
testLocalBindClassPermissions()1387     public void testLocalBindClassPermissions() throws Exception {
1388         bindExpectResult(mLocalGrantedService);
1389         bindExpectResult(mLocalDeniedService);
1390     }
1391 
1392     @MediumTest
testLocalBindActionPermissions()1393     public void testLocalBindActionPermissions() throws Exception {
1394         bindExpectResult(mLocalService_ApplicationHasPermission);
1395         bindExpectResult(mLocalService_ApplicationDoesNotHavePermission);
1396     }
1397 
1398     @MediumTest
testLocalBindAutoClassPermissionGranted()1399     public void testLocalBindAutoClassPermissionGranted() throws Exception {
1400         bindAutoExpectResult(mLocalGrantedService);
1401     }
1402 
1403     @MediumTest
testLocalBindAutoActionPermissionGranted()1404     public void testLocalBindAutoActionPermissionGranted() throws Exception {
1405         bindAutoExpectResult(mLocalService_ApplicationHasPermission);
1406     }
1407 
1408     @MediumTest
testLocalUnbindTwice()1409     public void testLocalUnbindTwice() throws Exception {
1410         EmptyConnection conn = new EmptyConnection();
1411         mContext.bindService(
1412                 mLocalService_ApplicationHasPermission, conn, 0);
1413         mContext.unbindService(conn);
1414         try {
1415             mContext.unbindService(conn);
1416             fail("No exception thrown on the second unbind");
1417         } catch (IllegalArgumentException e) {
1418             // expected
1419         }
1420     }
1421 
1422     @MediumTest
testImplicitIntentFailsOnApiLevel21()1423     public void testImplicitIntentFailsOnApiLevel21() throws Exception {
1424         Intent intent = new Intent(LocalService.SERVICE_LOCAL);
1425         EmptyConnection conn = new EmptyConnection();
1426         try {
1427             mContext.bindService(intent, conn, 0);
1428             mContext.unbindService(conn);
1429             fail("Implicit intents should be disallowed for apps targeting API 21+");
1430         } catch (IllegalArgumentException e) {
1431             // expected
1432         }
1433     }
1434 
1435     /**
1436      * Verify that when the requested service's onBind() returns null,
1437      * the connection's onNullBinding() method is invoked.
1438      */
1439     @MediumTest
testNullServiceBinder()1440     public void testNullServiceBinder() throws Exception {
1441         Intent intent = new Intent(mContext, NullService.class);
1442         intent.setAction("testNullServiceBinder");
1443         NullServiceConnection conn1 = new NullServiceConnection();
1444         NullServiceConnection conn2 = new NullServiceConnection();
1445         try {
1446             assertTrue(mContext.bindService(intent, conn1, Context.BIND_AUTO_CREATE));
1447             conn1.waitForNullBinding(DELAY);
1448             assertTrue(conn1.nullBindingReceived());
1449 
1450             assertTrue(mContext.bindService(intent, conn2, Context.BIND_AUTO_CREATE));
1451             conn2.waitForNullBinding(DELAY);
1452             assertTrue(conn2.nullBindingReceived());
1453         } finally {
1454             mContext.unbindService(conn1);
1455             mContext.unbindService(conn2);
1456         }
1457     }
1458 
1459     /**
1460      * Verify that we can't use bindIsolatedService() on a non-isolated service.
1461      */
1462     @MediumTest
testFailBindNonIsolatedService()1463     public void testFailBindNonIsolatedService() throws Exception {
1464         EmptyConnection conn = new EmptyConnection();
1465         try {
1466             mContext.bindIsolatedService(mLocalService, 0, "isolated", mContextMainExecutor, conn);
1467             mContext.unbindService(conn);
1468             fail("Didn't get IllegalArgumentException");
1469         } catch (IllegalArgumentException e) {
1470             // This is expected.
1471         }
1472     }
1473 
1474     /**
1475      * Verify that certain characters are prohibited in instanceName.
1476      */
testFailBindIsoaltedServiceWithInvalidInstanceName()1477     public void testFailBindIsoaltedServiceWithInvalidInstanceName() throws Exception {
1478         String[] badNames = {
1479             "t\rest",
1480             "test\n",
1481             "test-three",
1482             "test four",
1483             "escape\u00a9seq",
1484             "\u0164est",
1485         };
1486         for (String instanceName : badNames) {
1487             EmptyConnection conn = new EmptyConnection();
1488             try {
1489                 mContext.bindIsolatedService(mIsolatedService, Context.BIND_AUTO_CREATE,
1490                         instanceName, mContextMainExecutor, conn);
1491                 mContext.unbindService(conn);
1492                 fail("Didn't get IllegalArgumentException: " + instanceName);
1493             } catch (IllegalArgumentException e) {
1494                 // This is expected.
1495             }
1496         }
1497     }
1498 
1499     /**
1500      * Verify that bindIsolatedService() correctly makes different instances when given
1501      * different instance names.
1502      */
1503     @MediumTest
testBindIsolatedServiceInstances()1504     public void testBindIsolatedServiceInstances() throws Exception {
1505         IsolatedConnection conn1a = null;
1506         IsolatedConnection conn1b = null;
1507         IsolatedConnection conn2 = null;
1508         try {
1509             conn1a = new IsolatedConnection();
1510             mContext.bindIsolatedService(
1511                     mIsolatedService, Context.BIND_AUTO_CREATE, "1", mContextMainExecutor, conn1a);
1512             conn1b = new IsolatedConnection();
1513             mContext.bindIsolatedService(
1514                     mIsolatedService, Context.BIND_AUTO_CREATE, "1", mContextMainExecutor, conn1b);
1515             conn2 = new IsolatedConnection();
1516             mContext.bindIsolatedService(
1517                     mIsolatedService, Context.BIND_AUTO_CREATE, "2", mContextMainExecutor, conn2);
1518 
1519             conn1a.waitForService(DELAY);
1520             conn1b.waitForService(DELAY);
1521             conn2.waitForService(DELAY);
1522 
1523             if (conn1a.getPid() != conn1b.getPid()) {
1524                 fail("Connections to same service name in different pids");
1525             }
1526             if (conn1a.getPid() == conn2.getPid()) {
1527                 fail("Connections to different service names in same pids");
1528             }
1529 
1530             conn1a.setValue(1);
1531             assertEquals(1, conn1a.getValue());
1532             assertEquals(1, conn1b.getValue());
1533 
1534             conn2.setValue(2);
1535             assertEquals(1, conn1a.getValue());
1536             assertEquals(1, conn1b.getValue());
1537             assertEquals(2, conn2.getValue());
1538 
1539             conn1b.setValue(3);
1540             assertEquals(3, conn1a.getValue());
1541             assertEquals(3, conn1b.getValue());
1542             assertEquals(2, conn2.getValue());
1543         } finally {
1544             if (conn2 != null) {
1545                 mContext.unbindService(conn2);
1546             }
1547             if (conn1b != null) {
1548                 mContext.unbindService(conn1b);
1549             }
1550             if (conn1a != null) {
1551                 mContext.unbindService(conn1a);
1552             }
1553         }
1554     }
1555 
testBindIsolatedServiceOnBackgroundThread()1556     public void testBindIsolatedServiceOnBackgroundThread() throws Exception {
1557         setupBackgroundThread();
1558         IsolatedConnection conn = new IsolatedConnection();
1559         mContext.bindIsolatedService(mIsolatedService, Context.BIND_AUTO_CREATE,
1560             "background_instance", mBackgroundThreadExecutor, conn);
1561         conn.waitForService(DELAY);
1562         assertEquals(mBackgroundThread, conn.getOnServiceConnectedThread());
1563         mContext.unbindService(conn);
1564     }
1565 
1566     static final int BINDING_WEAK = 0;
1567     static final int BINDING_STRONG = 1;
1568     static final int BINDING_ANY = -1;
1569 
1570     final class IsolatedConnectionInfo {
1571         final int mStrong;
1572         final String mInstanceName;
1573         final String mLabel;
1574         int mGroup;
1575         int mImportance;
1576         IsolatedConnection mConnection;
1577 
IsolatedConnectionInfo(int group, int importance, int strong)1578         IsolatedConnectionInfo(int group, int importance, int strong) {
1579             mGroup = group;
1580             mImportance = importance;
1581             mStrong = strong;
1582             mInstanceName = group + "_" + importance;
1583             StringBuilder b = new StringBuilder(mInstanceName);
1584             b.append('_');
1585             if (strong == BINDING_WEAK) {
1586                 b.append('W');
1587             } else if (strong == BINDING_STRONG) {
1588                 b.append('S');
1589             } else {
1590                 b.append(strong);
1591             }
1592             mLabel = b.toString();
1593         }
1594 
setGroup(int group)1595         void setGroup(int group) {
1596             mGroup = group;
1597         }
1598 
setImportance(int importance)1599         void setImportance(int importance) {
1600             mImportance = importance;
1601         }
1602 
match(int group, int strong)1603         boolean match(int group, int strong) {
1604             return (group < 0 || mGroup == group)
1605                     && (strong == BINDING_ANY || mStrong == strong);
1606         }
1607 
bind(Context context)1608         boolean bind(Context context) {
1609             if (mConnection != null) {
1610                 return true;
1611             }
1612             Log.i("XXXXXXX", "Binding " + mLabel + ": conn=" + mConnection
1613                     + " context=" + context);
1614             mConnection = new IsolatedConnection();
1615             boolean result = context.bindIsolatedService(
1616                     mIsolatedService,
1617                     Context.BIND_AUTO_CREATE | Context.BIND_DEBUG_UNBIND
1618                             | (mStrong == BINDING_STRONG ? 0 : Context.BIND_ALLOW_OOM_MANAGEMENT),
1619                     mInstanceName, mContextMainExecutor, mConnection);
1620             if (!result) {
1621                 mConnection = null;
1622             }
1623             return result;
1624         }
1625 
getConnection()1626         IsolatedConnection getConnection() {
1627             return mConnection;
1628         }
1629 
unbind(Context context)1630         void unbind(Context context) {
1631             if (mConnection != null) {
1632                 Log.i("XXXXXXX", "Unbinding " + mLabel + ": conn=" + mConnection
1633                         + " context=" + context);
1634                 context.unbindService(mConnection);
1635                 mConnection = null;
1636             }
1637         }
1638     }
1639 
1640     final class LruOrderItem {
1641         static final int FLAG_SKIP_UNKNOWN = 1<<0;
1642 
1643         final IsolatedConnectionInfo mInfo;
1644         final int mUid;
1645         final int mFlags;
1646 
LruOrderItem(IsolatedConnectionInfo info, int flags)1647         LruOrderItem(IsolatedConnectionInfo info, int flags) {
1648             mInfo = info;
1649             mUid = -1;
1650             mFlags = flags;
1651         }
1652 
LruOrderItem(int uid, int flags)1653         LruOrderItem(int uid, int flags) {
1654             mInfo = null;
1655             mUid = uid;
1656             mFlags = flags;
1657         }
1658 
getInfo()1659         IsolatedConnectionInfo getInfo() {
1660             return mInfo;
1661         }
1662 
getUid()1663         int getUid() {
1664             return mInfo != null ? mInfo.getConnection().getUid() : mUid;
1665         }
1666 
getUserId()1667         int getUserId() {
1668             return UserHandle.getUserHandleForUid(getUid()).getIdentifier();
1669         }
1670 
getAppId()1671         int getAppId() {
1672             return UserHandle.getAppId(getUid());
1673         }
1674 
isEquivalentTo(ProcessRecordProto proc)1675         boolean isEquivalentTo(ProcessRecordProto proc) {
1676             int procAppId = proc.isolatedAppId != 0 ? proc.isolatedAppId : UserHandle.getAppId(
1677                     proc.uid);
1678 
1679             // Compare appid and userid separately because UserHandle.getUid is @hide.
1680             return procAppId == getAppId() && proc.userId == getUserId();
1681         }
1682 
getFlags()1683         int getFlags() {
1684             return mFlags;
1685         }
1686     }
1687 
doBind(Context context, IsolatedConnectionInfo[] connections, int group, int strong)1688     private void doBind(Context context, IsolatedConnectionInfo[] connections, int group,
1689             int strong) {
1690         for (IsolatedConnectionInfo ci : connections) {
1691             if (ci.match(group, strong)) {
1692                 ci.bind(context);
1693             }
1694         }
1695     }
1696 
doBind(Context context, IsolatedConnectionInfo[] connections, int[] selected)1697     private void doBind(Context context, IsolatedConnectionInfo[] connections, int[] selected) {
1698         for (int i : selected) {
1699             boolean result = connections[i].bind(context);
1700             if (!result) {
1701                 fail("Unable to bind connection " + connections[i].mLabel);
1702             }
1703         }
1704     }
1705 
doWaitForService(IsolatedConnectionInfo[] connections, int group, int strong)1706     private void doWaitForService(IsolatedConnectionInfo[] connections, int group,
1707             int strong) {
1708         for (IsolatedConnectionInfo ci : connections) {
1709             if (ci.match(group, strong)) {
1710                 ci.mConnection.waitForService(DELAY);
1711             }
1712         }
1713     }
1714 
doUpdateServiceGroup(Context context, IsolatedConnectionInfo[] connections, int group, int strong)1715     private void doUpdateServiceGroup(Context context, IsolatedConnectionInfo[] connections,
1716             int group, int strong) {
1717         for (IsolatedConnectionInfo ci : connections) {
1718             if (ci.match(group, strong)) {
1719                 context.updateServiceGroup(ci.mConnection, ci.mGroup, ci.mImportance);
1720             }
1721         }
1722     }
1723 
doUnbind(Context context, IsolatedConnectionInfo[] connections, int group, int strong)1724     private void doUnbind(Context context, IsolatedConnectionInfo[] connections, int group,
1725             int strong) {
1726         for (IsolatedConnectionInfo ci : connections) {
1727             if (ci.match(group, strong)) {
1728                 ci.unbind(context);
1729             }
1730         }
1731     }
1732 
doUnbind(Context context, IsolatedConnectionInfo[] connections, int[] selected)1733     private void doUnbind(Context context, IsolatedConnectionInfo[] connections, int[] selected) {
1734         for (int i : selected) {
1735             connections[i].unbind(context);
1736         }
1737     }
1738 
getLruProcesses()1739     List<ProcessRecordProto> getLruProcesses() {
1740         ActivityManagerServiceDumpProcessesProto dump = getActivityManagerProcesses();
1741         SparseArray<ProcessRecordProto> procs = new SparseArray<>();
1742         ProcessRecordProto[] procsList = dump.procs;
1743         for (ProcessRecordProto proc : procsList) {
1744             procs.put(proc.lruIndex, proc);
1745         }
1746         ArrayList<ProcessRecordProto> lruProcs = new ArrayList<>();
1747         for (int i = 0; i < procs.size(); i++) {
1748             lruProcs.add(procs.valueAt(i));
1749         }
1750         return lruProcs;
1751     }
1752 
printProc(int i, ProcessRecordProto proc)1753     String printProc(int i, ProcessRecordProto proc) {
1754         return "#" + i + ": " + proc.processName
1755                 + " pid=" + proc.pid + " uid=" + proc.uid
1756                 + (proc.isolatedAppId != 0 ? " isolated=" + proc.isolatedAppId : "");
1757     }
1758 
logProc(int i, ProcessRecordProto proc)1759     private void logProc(int i, ProcessRecordProto proc) {
1760         Log.i("XXXXXXXX", printProc(i, proc));
1761     }
1762 
verifyLruOrder(LruOrderItem[] orderItems)1763     private void verifyLruOrder(LruOrderItem[] orderItems) {
1764         List<ProcessRecordProto> procs = getLruProcesses();
1765         Log.i("XXXXXXXX", "Processes:");
1766         int orderI = 0;
1767         for (int i = procs.size() - 1; i >= 0; i--) {
1768             ProcessRecordProto proc = procs.get(i);
1769             logProc(i, proc);
1770             final LruOrderItem lru = orderItems[orderI];
1771             Log.i("XXXXXXXX", "Expecting uid: " + lru.getUid());
1772             if (!lru.isEquivalentTo(proc)) {
1773                 if ((lru.getFlags() & LruOrderItem.FLAG_SKIP_UNKNOWN) != 0) {
1774                     while (i > 0) {
1775                         i--;
1776                         proc = procs.get(i);
1777                         logProc(i, proc);
1778                         if (lru.isEquivalentTo(proc)) {
1779                             break;
1780                         }
1781                     }
1782                 }
1783                 if (!lru.isEquivalentTo(proc)) {
1784                     if ((lru.getFlags() & LruOrderItem.FLAG_SKIP_UNKNOWN) != 0) {
1785                         fail("Didn't find expected LRU proc uid=" + lru.getUid());
1786                     }
1787                     fail("Expected proc uid=" + lru.getUid() + " at found proc "
1788                             + printProc(i, proc));
1789                 }
1790             }
1791             orderI++;
1792             if (orderI >= orderItems.length) {
1793                 return;
1794             }
1795         }
1796     }
1797 
1798     @MediumTest
testAppZygotePreload()1799     public void testAppZygotePreload() throws Exception {
1800         IsolatedConnection conn = new IsolatedConnection();
1801         try {
1802             mContext.bindIsolatedService(
1803                     mIsolatedService, Context.BIND_AUTO_CREATE, "1", mContextMainExecutor, conn);
1804 
1805             conn.waitForService(DELAY);
1806 
1807             // Verify application preload was done
1808             assertTrue(conn.zygotePreloadCalled());
1809         } finally {
1810             if (conn != null) {
1811                 mContext.unbindService(conn);
1812             }
1813         }
1814     }
1815 
1816     @MediumTest
testAppZygoteServices()1817     public void testAppZygoteServices() throws Exception {
1818         IsolatedConnection conn1a = null;
1819         IsolatedConnection conn1b = null;
1820         IsolatedConnection conn2 = null;
1821         int appZygotePid;
1822         try {
1823             conn1a = new IsolatedConnection();
1824             mContext.bindIsolatedService(
1825                     mIsolatedService, Context.BIND_AUTO_CREATE, "1", mContextMainExecutor, conn1a);
1826             conn1b = new IsolatedConnection();
1827             mContext.bindIsolatedService(
1828                     mIsolatedService, Context.BIND_AUTO_CREATE, "1", mContextMainExecutor, conn1b);
1829             conn2 = new IsolatedConnection();
1830             mContext.bindIsolatedService(
1831                     mIsolatedService, Context.BIND_AUTO_CREATE, "2", mContextMainExecutor, conn2);
1832 
1833             conn1a.waitForService(DELAY);
1834             conn1b.waitForService(DELAY);
1835             conn2.waitForService(DELAY);
1836 
1837             // Get PPID of each service, and verify they're identical
1838             int ppid1a = conn1a.getPpid();
1839             int ppid1b = conn1b.getPpid();
1840             int ppid2 = conn2.getPpid();
1841 
1842             assertEquals(ppid1a, ppid1b);
1843             assertEquals(ppid1b, ppid2);
1844             // Find the app zygote process hosting these
1845             String result = SystemUtil.runShellCommand(InstrumentationRegistry.getInstrumentation(),
1846                 "ps -p " + Integer.toString(ppid1a) + " -o NAME=");
1847             result = result.replaceAll("\\s+", "");
1848             assertEquals(result, APP_ZYGOTE_PROCESS_NAME);
1849             appZygotePid = ppid1a;
1850         } finally {
1851             if (conn2 != null) {
1852                 mContext.unbindService(conn2);
1853             }
1854             if (conn1b != null) {
1855                 mContext.unbindService(conn1b);
1856             }
1857             if (conn1a != null) {
1858                 mContext.unbindService(conn1a);
1859             }
1860         }
1861         // Sleep for 2 seconds and bind a service again, see it uses the same Zygote
1862         try {
1863             conn1a = new IsolatedConnection();
1864             mContext.bindIsolatedService(
1865                     mIsolatedService, Context.BIND_AUTO_CREATE, "1", mContextMainExecutor, conn1a);
1866 
1867             conn1a.waitForService(DELAY);
1868 
1869             int ppid1a = conn1a.getPpid();
1870             assertEquals(appZygotePid, ppid1a);
1871         } finally {
1872             if (conn1a != null) {
1873                 mContext.unbindService(conn1a);
1874             }
1875         }
1876         // Sleep for 10 seconds, verify the app_zygote is gone
1877         Thread.sleep(10000);
1878         String result = SystemUtil.runShellCommand(InstrumentationRegistry.getInstrumentation(),
1879             "ps -p " + Integer.toString(appZygotePid) + " -o NAME=");
1880         result = result.replaceAll("\\s+", "");
1881         assertEquals("", result);
1882     }
1883 
1884     /**
1885      * Test that the system properly orders processes bound by an activity within the
1886      * LRU list.
1887      */
1888     // TODO(b/131059432): Re-enable the test after that bug is fixed.
1889     @FlakyTest
1890     @MediumTest
testActivityServiceBindingLru()1891     public void testActivityServiceBindingLru() throws Exception {
1892         // Bring up the activity we will hang services off of.
1893         runLaunchpad(LaunchpadActivity.ACTIVITY_PREPARE);
1894 
1895         final Activity a = getRunningActivity();
1896 
1897         final int CONN_1_1_W = 0;
1898         final int CONN_1_1_S = 1;
1899         final int CONN_1_2_W = 2;
1900         final int CONN_1_2_S = 3;
1901         final int CONN_2_1_W = 4;
1902         final int CONN_2_1_S = 5;
1903         final int CONN_2_2_W = 6;
1904         final int CONN_2_2_S = 7;
1905         final int CONN_2_3_W = 8;
1906         final int CONN_2_3_S = 9;
1907 
1908         // We are going to have both weak and strong references to services, so we can allow
1909         // some to go down in the LRU list.
1910         final IsolatedConnectionInfo[] connections = new IsolatedConnectionInfo[] {
1911                 new IsolatedConnectionInfo(1, 1, BINDING_WEAK),
1912                 new IsolatedConnectionInfo(1, 1, BINDING_STRONG),
1913                 new IsolatedConnectionInfo(1, 2, BINDING_WEAK),
1914                 new IsolatedConnectionInfo(1, 2, BINDING_STRONG),
1915                 new IsolatedConnectionInfo(2, 1, BINDING_WEAK),
1916                 new IsolatedConnectionInfo(2, 1, BINDING_STRONG),
1917                 new IsolatedConnectionInfo(2, 2, BINDING_WEAK),
1918                 new IsolatedConnectionInfo(2, 2, BINDING_STRONG),
1919                 new IsolatedConnectionInfo(2, 3, BINDING_WEAK),
1920                 new IsolatedConnectionInfo(2, 3, BINDING_STRONG),
1921         };
1922 
1923         final int[] REV_GROUP_1_STRONG = new int[] {
1924                 CONN_1_2_S, CONN_1_1_S
1925         };
1926 
1927         final int[] REV_GROUP_2_STRONG = new int[] {
1928                 CONN_2_3_S, CONN_2_2_S, CONN_2_1_S
1929         };
1930 
1931         final int[] MIXED_GROUP_3_STRONG = new int[] {
1932                 CONN_2_3_S, CONN_1_1_S, CONN_2_1_S, CONN_2_2_S
1933         };
1934 
1935         boolean passed = false;
1936 
1937         try {
1938             // Start the group 1 processes as weak.
1939             doBind(a, connections, 1, BINDING_WEAK);
1940             doUpdateServiceGroup(a, connections, 1, BINDING_WEAK);
1941 
1942             // Wait for them to come up.
1943             doWaitForService(connections, 1, BINDING_WEAK);
1944 
1945             // Now fully bind to the services.
1946             doBind(a, connections, 1, BINDING_STRONG);
1947             doWaitForService(connections, 1, BINDING_STRONG);
1948 
1949             verifyLruOrder(new LruOrderItem[] {
1950                     new LruOrderItem(Process.myUid(), 0),
1951                     new LruOrderItem(connections[CONN_1_1_W], 0),
1952                     new LruOrderItem(connections[CONN_1_2_W], 0),
1953             });
1954 
1955             // Now remove the full binding, leaving only the weak.
1956             doUnbind(a, connections, 1, BINDING_STRONG);
1957 
1958             // Start the group 2 processes as weak.
1959             doBind(a, connections, 2, BINDING_WEAK);
1960 
1961             // Wait for them to come up.
1962             doWaitForService(connections, 2, BINDING_WEAK);
1963 
1964             // Set the group and index.  In this case we do it after we know the process
1965             // is started, to make sure setting it directly works.
1966             doUpdateServiceGroup(a, connections, 2, BINDING_WEAK);
1967 
1968             // Now fully bind to group 2
1969             doBind(a, connections, REV_GROUP_2_STRONG);
1970 
1971             verifyLruOrder(new LruOrderItem[] {
1972                     new LruOrderItem(Process.myUid(), 0),
1973                     new LruOrderItem(connections[CONN_2_1_W], 0),
1974                     new LruOrderItem(connections[CONN_2_2_W], 0),
1975                     new LruOrderItem(connections[CONN_2_3_W], 0),
1976                     new LruOrderItem(connections[CONN_1_1_W], LruOrderItem.FLAG_SKIP_UNKNOWN),
1977                     new LruOrderItem(connections[CONN_1_2_W], 0),
1978             });
1979 
1980             // Bring group 1 back to the foreground, but in the opposite order.
1981             doBind(a, connections, REV_GROUP_1_STRONG);
1982 
1983             verifyLruOrder(new LruOrderItem[] {
1984                     new LruOrderItem(Process.myUid(), 0),
1985                     new LruOrderItem(connections[CONN_1_1_W], 0),
1986                     new LruOrderItem(connections[CONN_1_2_W], 0),
1987                     new LruOrderItem(connections[CONN_2_1_W], LruOrderItem.FLAG_SKIP_UNKNOWN),
1988                     new LruOrderItem(connections[CONN_2_2_W], 0),
1989                     new LruOrderItem(connections[CONN_2_3_W], 0),
1990             });
1991 
1992             // Now remove all full bindings, keeping only weak.
1993             doUnbind(a, connections, 1, BINDING_STRONG);
1994             doUnbind(a, connections, 2, BINDING_STRONG);
1995 
1996             // Change the grouping and importance to make sure that gets reflected.
1997             connections[CONN_1_1_W].setGroup(3);
1998             connections[CONN_1_1_W].setImportance(1);
1999             connections[CONN_2_1_W].setGroup(3);
2000             connections[CONN_2_1_W].setImportance(2);
2001             connections[CONN_2_2_W].setGroup(3);
2002             connections[CONN_2_2_W].setImportance(3);
2003             connections[CONN_2_3_W].setGroup(3);
2004             connections[CONN_2_3_W].setImportance(4);
2005 
2006             doUpdateServiceGroup(a, connections, 3, BINDING_WEAK);
2007 
2008             // Now bind them back up in an interesting order.
2009             doBind(a, connections, MIXED_GROUP_3_STRONG);
2010 
2011             verifyLruOrder(new LruOrderItem[] {
2012                     new LruOrderItem(Process.myUid(), 0),
2013                     new LruOrderItem(connections[CONN_1_1_W], 0),
2014                     new LruOrderItem(connections[CONN_2_1_W], 0),
2015                     new LruOrderItem(connections[CONN_2_2_W], 0),
2016                     new LruOrderItem(connections[CONN_2_3_W], 0),
2017                     new LruOrderItem(connections[CONN_1_2_W], LruOrderItem.FLAG_SKIP_UNKNOWN),
2018             });
2019 
2020             passed = true;
2021 
2022         } finally {
2023             if (!passed) {
2024                 List<ProcessRecordProto> procs = getLruProcesses();
2025                 Log.i("XXXXXXXX", "Processes:");
2026                 for (int i = procs.size() - 1; i >= 0; i--) {
2027                     ProcessRecordProto proc = procs.get(i);
2028                     logProc(i, proc);
2029                 }
2030             }
2031             doUnbind(a, connections, -1, BINDING_ANY);
2032         }
2033     }
2034 }
2035