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