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