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