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