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