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