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