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