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