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