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