1 /* 2 * Copyright (C) 2021 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 com.android.server.am; 18 19 import static com.android.internal.app.procstats.ProcessStats.ADJ_MEM_FACTOR_LOW; 20 import static com.android.internal.app.procstats.ProcessStats.ADJ_MEM_FACTOR_MODERATE; 21 import static com.android.internal.app.procstats.ProcessStats.ADJ_MEM_FACTOR_NORMAL; 22 23 import static org.junit.Assert.assertFalse; 24 import static org.junit.Assert.assertNotNull; 25 import static org.junit.Assert.assertTrue; 26 27 import android.app.ActivityManager; 28 import android.app.ActivityManager.OnUidImportanceListener; 29 import android.app.ActivityManager.RunningAppProcessInfo; 30 import android.app.Instrumentation; 31 import android.content.ComponentName; 32 import android.content.Context; 33 import android.content.Intent; 34 import android.content.ServiceConnection; 35 import android.content.pm.ApplicationInfo; 36 import android.os.IBinder; 37 import android.os.SystemClock; 38 import android.provider.DeviceConfig; 39 import android.provider.Settings; 40 import android.server.wm.settings.SettingsSession; 41 import android.util.Log; 42 43 import androidx.test.InstrumentationRegistry; 44 import androidx.test.filters.LargeTest; 45 import androidx.test.runner.AndroidJUnit4; 46 47 import com.android.compatibility.common.util.SystemUtil; 48 49 import org.junit.After; 50 import org.junit.Before; 51 import org.junit.Test; 52 import org.junit.runner.RunWith; 53 54 import java.util.concurrent.CountDownLatch; 55 import java.util.concurrent.TimeUnit; 56 import java.util.regex.Matcher; 57 import java.util.regex.Pattern; 58 59 /** 60 * Build/Install/Run: 61 * atest FrameworksServicesTests:ServiceRestarterTest 62 */ 63 @RunWith(AndroidJUnit4.class) 64 public final class ServiceRestarterTest { 65 private static final String TAG = "ServiceRestarterTest"; 66 67 private static final String TEST_PACKAGE1_NAME = 68 "com.android.servicestests.apps.simpleservicetestapp1"; 69 private static final String TEST_PACKAGE2_NAME = 70 "com.android.servicestests.apps.simpleservicetestapp2"; 71 private static final String TEST_PACKAGE3_NAME = 72 "com.android.servicestests.apps.simpleservicetestapp3"; 73 private static final String TEST_SERVICE_NAME = 74 "com.android.servicestests.apps.simpleservicetestapp.SimpleService"; 75 private static final String[] MEMORY_PRESSURE_MAP = { 76 "NORMAL", "MODERATE", "LOW", "CRITICAL"}; 77 private static final String EXTRA_DELAY = "0,2000,4000,8000"; 78 private static final int SERVICE_RESTART_DURATION_FACTOR = 2; 79 private static final long BOUND_SERVICE_CRASH_RESTART_DURATION = 1000; 80 private static final long SERVICE_MIN_RESTART_TIME_BETWEEN = 1000; 81 82 private static final long WAIT_MS = 5 * 1000; 83 private static final long WAIT_LONG_MS = 30 * 1000; 84 85 private static final int ACTION_START = 1; 86 private static final int ACTION_KILL = 2; 87 private static final int ACTION_WAIT = 4; 88 private static final int ACTION_STOPPKG = 8; 89 private static final int ACTION_ALL = ACTION_START | ACTION_KILL | ACTION_WAIT | ACTION_STOPPKG; 90 91 private static final String LOCAL_APK_BASE_PATH = "/data/local/tmp/cts/content/"; 92 private static final String TEST_PACKAGE3_APK = "SimpleServiceTestApp3.apk"; 93 private static final String ACTION_SERVICE_WITH_DEP_PKG = 94 "com.android.servicestests.apps.simpleservicetestapp.ACTION_SERVICE_WITH_DEP_PKG"; 95 private static final String EXTRA_TARGET_PACKAGE = "target_package"; 96 97 private SettingsSession<String> mAMConstantsSettings; 98 private DeviceConfigSession<String> mExtraDelaysDeviceConfig; 99 private DeviceConfigSession<Boolean> mEnableExtraDelaysDeviceConfig; 100 101 private Context mContext; 102 private Instrumentation mInstrumentation; 103 private int mTestPackage1Uid; 104 private int mTestPackage2Uid; 105 private int mTestPackage3Uid; 106 107 @Before setUp()108 public void setUp() throws Exception { 109 mInstrumentation = InstrumentationRegistry.getInstrumentation(); 110 mContext = InstrumentationRegistry.getContext(); 111 ApplicationInfo ai = mContext.getPackageManager().getApplicationInfo(TEST_PACKAGE1_NAME, 0); 112 mTestPackage1Uid = ai.uid; 113 ai = mContext.getPackageManager().getApplicationInfo(TEST_PACKAGE2_NAME, 0); 114 mTestPackage2Uid = ai.uid; 115 ai = mContext.getPackageManager().getApplicationInfo(TEST_PACKAGE3_NAME, 0); 116 mTestPackage3Uid = ai.uid; 117 final String activityManagerConstants = Settings.Global.ACTIVITY_MANAGER_CONSTANTS; 118 mAMConstantsSettings = new SettingsSession<>( 119 Settings.Global.getUriFor(activityManagerConstants), 120 Settings.Global::getString, Settings.Global::putString); 121 mAMConstantsSettings.set( 122 ActivityManagerConstants.KEY_SERVICE_RESTART_DURATION_FACTOR + "=" 123 + SERVICE_RESTART_DURATION_FACTOR + "," 124 + ActivityManagerConstants.KEY_BOUND_SERVICE_CRASH_RESTART_DURATION + "=" 125 + BOUND_SERVICE_CRASH_RESTART_DURATION + "," 126 + ActivityManagerConstants.KEY_SERVICE_MIN_RESTART_TIME_BETWEEN + "=" 127 + SERVICE_MIN_RESTART_TIME_BETWEEN); 128 mExtraDelaysDeviceConfig = new DeviceConfigSession<>( 129 DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 130 ActivityManagerConstants.KEY_EXTRA_SERVICE_RESTART_DELAY_ON_MEM_PRESSURE, 131 DeviceConfig::getString, null); 132 mExtraDelaysDeviceConfig.set(EXTRA_DELAY); 133 mEnableExtraDelaysDeviceConfig = new DeviceConfigSession<>( 134 DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 135 ActivityManagerConstants.KEY_ENABLE_EXTRA_SERVICE_RESTART_DELAY_ON_MEM_PRESSURE, 136 DeviceConfig::getBoolean, false); 137 mEnableExtraDelaysDeviceConfig.set(true); 138 } 139 140 @After tearDown()141 public void tearDown() throws Exception { 142 if (mAMConstantsSettings != null) { 143 mAMConstantsSettings.close(); 144 } 145 if (mExtraDelaysDeviceConfig != null) { 146 mExtraDelaysDeviceConfig.close(); 147 } 148 if (mEnableExtraDelaysDeviceConfig != null) { 149 mEnableExtraDelaysDeviceConfig.close(); 150 } 151 } 152 153 @LargeTest 154 @Test testDisableServiceRestartBackoff()155 public void testDisableServiceRestartBackoff() throws Exception { 156 final ActivityManager am = mContext.getSystemService(ActivityManager.class); 157 final MyUidImportanceListener uid1Listener1 = new MyUidImportanceListener(mTestPackage1Uid); 158 final MyUidImportanceListener uid1Listener2 = new MyUidImportanceListener(mTestPackage1Uid); 159 final MyUidImportanceListener uid2Listener1 = new MyUidImportanceListener(mTestPackage2Uid); 160 final MyUidImportanceListener uid2Listener2 = new MyUidImportanceListener(mTestPackage2Uid); 161 final MyUidImportanceListener uid3Listener1 = new MyUidImportanceListener(mTestPackage3Uid); 162 final MyUidImportanceListener uid3Listener2 = new MyUidImportanceListener(mTestPackage3Uid); 163 try { 164 am.addOnUidImportanceListener(uid1Listener1, RunningAppProcessInfo.IMPORTANCE_SERVICE); 165 am.addOnUidImportanceListener(uid1Listener2, RunningAppProcessInfo.IMPORTANCE_GONE); 166 am.addOnUidImportanceListener(uid2Listener1, RunningAppProcessInfo.IMPORTANCE_SERVICE); 167 am.addOnUidImportanceListener(uid2Listener2, RunningAppProcessInfo.IMPORTANCE_GONE); 168 am.addOnUidImportanceListener(uid3Listener1, RunningAppProcessInfo.IMPORTANCE_SERVICE); 169 am.addOnUidImportanceListener(uid3Listener2, RunningAppProcessInfo.IMPORTANCE_GONE); 170 executeShellCmd("cmd deviceidle whitelist +" + TEST_PACKAGE1_NAME); 171 executeShellCmd("cmd deviceidle whitelist +" + TEST_PACKAGE2_NAME); 172 executeShellCmd("cmd deviceidle whitelist +" + TEST_PACKAGE3_NAME); 173 174 // Issue the command to enable service backoff policy for app2. 175 executeShellCmd("am service-restart-backoff enable " + TEST_PACKAGE2_NAME); 176 // Test restarts in normal case 177 final long[] ts1 = startKillAndRestart(am, ACTION_START | ACTION_KILL | ACTION_WAIT, 178 uid1Listener1, uid1Listener2, uid2Listener1, uid2Listener2, 179 uid3Listener1, uid3Listener2, Long.MAX_VALUE, false); 180 assertTrue("app1 restart should be before app2", ts1[1] < ts1[2]); 181 assertTrue("app2 restart should be before app3", ts1[2] < ts1[3]); 182 183 // Issue the command to disable service backoff policy for app2. 184 executeShellCmd("am service-restart-backoff disable " + TEST_PACKAGE2_NAME); 185 // Test restarts again. 186 final long[] ts2 = startKillAndRestart(am, ACTION_KILL | ACTION_WAIT | ACTION_STOPPKG, 187 uid1Listener1, uid1Listener2, uid2Listener1, 188 uid2Listener2, uid3Listener1, uid3Listener2, Long.MAX_VALUE, false); 189 assertTrue("app2 restart should be before app1", ts2[2] < ts2[1]); 190 assertTrue("app1 restart should be before app3", ts2[1] < ts2[3]); 191 assertTrue("app2 should be restart in a very short moment", ts2[2] - ts2[0] < WAIT_MS); 192 193 // Issue the command to enable service backoff policy for app2. 194 executeShellCmd("am service-restart-backoff enable " + TEST_PACKAGE2_NAME); 195 // Test restarts again. 196 final long[] ts3 = startKillAndRestart(am, ACTION_ALL, uid1Listener1, uid1Listener2, 197 uid2Listener1, uid2Listener2, uid3Listener1, uid3Listener2, Long.MAX_VALUE, 198 false); 199 assertTrue("app1 restart should be before app2", ts3[1] < ts3[2]); 200 assertTrue("app2 restart should be before app3", ts3[2] < ts3[3]); 201 202 } finally { 203 executeShellCmd("cmd deviceidle whitelist -" + TEST_PACKAGE1_NAME); 204 executeShellCmd("cmd deviceidle whitelist -" + TEST_PACKAGE2_NAME); 205 executeShellCmd("cmd deviceidle whitelist -" + TEST_PACKAGE3_NAME); 206 executeShellCmd("am service-restart-backoff enable " + TEST_PACKAGE2_NAME); 207 am.removeOnUidImportanceListener(uid1Listener1); 208 am.removeOnUidImportanceListener(uid1Listener2); 209 am.removeOnUidImportanceListener(uid2Listener1); 210 am.removeOnUidImportanceListener(uid2Listener2); 211 am.removeOnUidImportanceListener(uid3Listener1); 212 am.removeOnUidImportanceListener(uid3Listener2); 213 am.forceStopPackage(TEST_PACKAGE1_NAME); 214 am.forceStopPackage(TEST_PACKAGE2_NAME); 215 am.forceStopPackage(TEST_PACKAGE3_NAME); 216 } 217 } 218 219 @LargeTest 220 @Test testExtraDelaysInServiceRestartOnLowMem()221 public void testExtraDelaysInServiceRestartOnLowMem() throws Exception { 222 final ActivityManager am = mContext.getSystemService(ActivityManager.class); 223 final MyUidImportanceListener uid1Listener1 = new MyUidImportanceListener(mTestPackage1Uid); 224 final MyUidImportanceListener uid1Listener2 = new MyUidImportanceListener(mTestPackage1Uid); 225 final MyUidImportanceListener uid2Listener1 = new MyUidImportanceListener(mTestPackage2Uid); 226 final MyUidImportanceListener uid2Listener2 = new MyUidImportanceListener(mTestPackage2Uid); 227 final MyUidImportanceListener uid3Listener1 = new MyUidImportanceListener(mTestPackage3Uid); 228 final MyUidImportanceListener uid3Listener2 = new MyUidImportanceListener(mTestPackage3Uid); 229 try { 230 am.addOnUidImportanceListener(uid1Listener1, RunningAppProcessInfo.IMPORTANCE_SERVICE); 231 am.addOnUidImportanceListener(uid1Listener2, RunningAppProcessInfo.IMPORTANCE_GONE); 232 am.addOnUidImportanceListener(uid2Listener1, RunningAppProcessInfo.IMPORTANCE_SERVICE); 233 am.addOnUidImportanceListener(uid2Listener2, RunningAppProcessInfo.IMPORTANCE_GONE); 234 am.addOnUidImportanceListener(uid3Listener1, RunningAppProcessInfo.IMPORTANCE_SERVICE); 235 am.addOnUidImportanceListener(uid3Listener2, RunningAppProcessInfo.IMPORTANCE_GONE); 236 executeShellCmd("cmd deviceidle whitelist +" + TEST_PACKAGE1_NAME); 237 executeShellCmd("cmd deviceidle whitelist +" + TEST_PACKAGE2_NAME); 238 executeShellCmd("cmd deviceidle whitelist +" + TEST_PACKAGE3_NAME); 239 240 // Force the memory pressure to normal. 241 setMemoryPressure(ADJ_MEM_FACTOR_NORMAL); 242 243 // Test restarts in normal condition. 244 final long[] ts1 = startKillAndRestart(am, ACTION_ALL, uid1Listener1, uid1Listener2, 245 uid2Listener1, uid2Listener2, uid3Listener1, uid3Listener2, WAIT_LONG_MS, true); 246 247 // Mimic a memory pressure event. 248 setMemoryPressure(ADJ_MEM_FACTOR_MODERATE); 249 250 final long[] ts2 = startKillAndRestart(am, ACTION_ALL, uid1Listener1, uid1Listener2, 251 uid2Listener1, uid2Listener2, uid3Listener1, uid3Listener2, WAIT_LONG_MS, true); 252 253 assertTrue("Expect extra delays in service restarts", 254 (ts2[1] - ts2[0]) > (ts1[1] - ts1[0])); 255 assertTrue("Expect extra delays in service restarts", 256 (ts2[2] - ts2[0]) > (ts1[2] - ts1[0])); 257 assertTrue("Expect extra delays in service restarts", 258 (ts2[3] - ts2[0]) > (ts1[3] - ts1[0])); 259 260 // Increase the memory pressure event. 261 setMemoryPressure(ADJ_MEM_FACTOR_LOW); 262 263 final long[] ts3 = startKillAndRestart(am, ACTION_ALL, uid1Listener1, uid1Listener2, 264 uid2Listener1, uid2Listener2, uid3Listener1, uid3Listener2, WAIT_LONG_MS, true); 265 266 assertTrue("Expect extra delays in service restarts", 267 (ts3[1] - ts3[0]) > (ts2[1] - ts2[0])); 268 assertTrue("Expect extra delays in service restarts", 269 (ts3[2] - ts3[0]) > (ts2[2] - ts2[0])); 270 assertTrue("Expect extra delays in service restarts", 271 (ts3[3] - ts3[0]) > (ts2[3] - ts2[0])); 272 273 // Start and kill them again, but don't wait for the restart. 274 final long now4 = startKillAndRestart(am, ACTION_START | ACTION_KILL, uid1Listener1, 275 uid1Listener2, uid2Listener1, uid2Listener2, uid3Listener1, uid3Listener2, 276 WAIT_LONG_MS, true)[0]; 277 278 // Set the memory pressure to normal. 279 setMemoryPressure(ADJ_MEM_FACTOR_NORMAL); 280 281 // Now wait for the restarts. 282 final long[] ts4 = startKillAndRestart(am, ACTION_WAIT | ACTION_STOPPKG, uid1Listener1, 283 uid1Listener2, uid2Listener1, uid2Listener2, uid3Listener1, uid3Listener2, 284 WAIT_LONG_MS, true); 285 286 assertTrue("Expect less delays in service restarts", 287 (ts4[1] - now4) < (ts2[1] - ts2[0])); 288 assertTrue("Expect less delays in service restarts", 289 (ts4[2] - now4) < (ts2[2] - ts2[0])); 290 assertTrue("Expect less delays in service restarts", 291 (ts4[3] - now4) < (ts2[3] - ts2[0])); 292 } finally { 293 executeShellCmd("cmd deviceidle whitelist -" + TEST_PACKAGE1_NAME); 294 executeShellCmd("cmd deviceidle whitelist -" + TEST_PACKAGE2_NAME); 295 executeShellCmd("cmd deviceidle whitelist -" + TEST_PACKAGE3_NAME); 296 resetMemoryPressure(); 297 am.removeOnUidImportanceListener(uid1Listener1); 298 am.removeOnUidImportanceListener(uid1Listener2); 299 am.removeOnUidImportanceListener(uid2Listener1); 300 am.removeOnUidImportanceListener(uid2Listener2); 301 am.removeOnUidImportanceListener(uid3Listener1); 302 am.removeOnUidImportanceListener(uid3Listener2); 303 am.forceStopPackage(TEST_PACKAGE1_NAME); 304 am.forceStopPackage(TEST_PACKAGE2_NAME); 305 am.forceStopPackage(TEST_PACKAGE3_NAME); 306 } 307 } 308 startKillAndRestart(ActivityManager am, int action, MyUidImportanceListener uid1Listener1, MyUidImportanceListener uid1Listener2, MyUidImportanceListener uid2Listener1, MyUidImportanceListener uid2Listener2, MyUidImportanceListener uid3Listener1, MyUidImportanceListener uid3Listener2, long waitDuration, boolean checkStartSeq)309 private long[] startKillAndRestart(ActivityManager am, int action, 310 MyUidImportanceListener uid1Listener1, MyUidImportanceListener uid1Listener2, 311 MyUidImportanceListener uid2Listener1, MyUidImportanceListener uid2Listener2, 312 MyUidImportanceListener uid3Listener1, MyUidImportanceListener uid3Listener2, 313 long waitDuration, boolean checkStartSeq) throws Exception { 314 final long[] res = new long[4]; 315 // Test restarts in normal condition. 316 if ((action & ACTION_START) != 0) { 317 startServiceAndWait(TEST_PACKAGE1_NAME, uid1Listener1, WAIT_MS); 318 startServiceAndWait(TEST_PACKAGE2_NAME, uid2Listener1, WAIT_MS); 319 startServiceAndWait(TEST_PACKAGE3_NAME, uid3Listener1, WAIT_MS); 320 } 321 322 if ((action & ACTION_KILL) != 0) { 323 final long now = res[0] = SystemClock.uptimeMillis(); 324 killUidAndWait(am, mTestPackage1Uid, uid1Listener2, WAIT_MS); 325 killUidAndWait(am, mTestPackage2Uid, uid2Listener2, WAIT_MS); 326 killUidAndWait(am, mTestPackage3Uid, uid3Listener2, WAIT_MS); 327 } 328 329 if ((action & ACTION_WAIT) != 0) { 330 assertTrue("Timed out to restart " + TEST_PACKAGE1_NAME, uid1Listener1.waitFor( 331 RunningAppProcessInfo.IMPORTANCE_SERVICE, waitDuration)); 332 assertTrue("Timed out to restart " + TEST_PACKAGE2_NAME, uid2Listener1.waitFor( 333 RunningAppProcessInfo.IMPORTANCE_SERVICE, waitDuration)); 334 assertTrue("Timed out to restart " + TEST_PACKAGE3_NAME, uid3Listener1.waitFor( 335 RunningAppProcessInfo.IMPORTANCE_SERVICE, waitDuration)); 336 final long uid1RestartTime = res[1] = uid1Listener1.mCurrentTimestamp; 337 final long uid2RestartTime = res[2] = uid2Listener1.mCurrentTimestamp; 338 final long uid3RestartTime = res[3] = uid3Listener1.mCurrentTimestamp; 339 if (checkStartSeq) { 340 assertTrue(TEST_PACKAGE1_NAME + " should restart before " + TEST_PACKAGE2_NAME, 341 uid1RestartTime <= uid2RestartTime); 342 assertTrue(TEST_PACKAGE2_NAME + " should restart before " + TEST_PACKAGE3_NAME, 343 uid2RestartTime <= uid3RestartTime); 344 } 345 } 346 347 if ((action & ACTION_STOPPKG) != 0) { 348 // Force stop these packages to reset the backoff delays. 349 am.forceStopPackage(TEST_PACKAGE1_NAME); 350 am.forceStopPackage(TEST_PACKAGE2_NAME); 351 am.forceStopPackage(TEST_PACKAGE3_NAME); 352 assertTrue("Timed out to force-stop " + mTestPackage1Uid, 353 uid1Listener2.waitFor(RunningAppProcessInfo.IMPORTANCE_GONE, WAIT_MS)); 354 assertTrue("Timed out to force-stop " + mTestPackage2Uid, 355 uid2Listener2.waitFor(RunningAppProcessInfo.IMPORTANCE_GONE, WAIT_MS)); 356 assertTrue("Timed out to force-stop " + mTestPackage3Uid, 357 uid3Listener2.waitFor(RunningAppProcessInfo.IMPORTANCE_GONE, WAIT_MS)); 358 } 359 return res; 360 } 361 362 @Test testServiceWithDepPkgStopped()363 public void testServiceWithDepPkgStopped() throws Exception { 364 final CountDownLatch[] latchHolder = new CountDownLatch[1]; 365 final ServiceConnection conn = new ServiceConnection() { 366 @Override 367 public void onServiceConnected(ComponentName name, IBinder service) { 368 latchHolder[0].countDown(); 369 } 370 371 @Override 372 public void onServiceDisconnected(ComponentName name) { 373 latchHolder[0].countDown(); 374 } 375 }; 376 377 final long timeout = 5_000; 378 final long shortTimeout = 2_000; 379 final Intent intent = new Intent(ACTION_SERVICE_WITH_DEP_PKG); 380 final String testPkg = TEST_PACKAGE2_NAME; 381 final String libPkg = TEST_PACKAGE3_NAME; 382 final String apkPath = LOCAL_APK_BASE_PATH + TEST_PACKAGE3_APK; 383 final ActivityManager am = mContext.getSystemService(ActivityManager.class); 384 385 intent.setComponent(ComponentName.unflattenFromString(testPkg + "/" + TEST_SERVICE_NAME)); 386 intent.putExtra(EXTRA_TARGET_PACKAGE, libPkg); 387 try { 388 executeShellCmd("am service-restart-backoff disable " + testPkg); 389 390 latchHolder[0] = new CountDownLatch(1); 391 assertTrue("Unable to bind to test service in " + testPkg, 392 mContext.bindService(intent, conn, Context.BIND_AUTO_CREATE)); 393 assertTrue("Timed out to bind service in " + testPkg, 394 latchHolder[0].await(timeout, TimeUnit.MILLISECONDS)); 395 396 Thread.sleep(shortTimeout); 397 assertTrue(libPkg + " should be a dependency package of " + testPkg, 398 isPackageDependency(testPkg, libPkg)); 399 400 // Force-stop lib package, the test service should be restarted. 401 latchHolder[0] = new CountDownLatch(2); 402 am.forceStopPackage(libPkg); 403 assertTrue("Test service in didn't restart in " + testPkg, 404 latchHolder[0].await(timeout, TimeUnit.MILLISECONDS)); 405 406 Thread.sleep(shortTimeout); 407 408 // Re-install the lib package, the test service should be restarted. 409 latchHolder[0] = new CountDownLatch(2); 410 assertTrue("Unable to install package " + apkPath, installPackage(apkPath)); 411 assertTrue("Test service in didn't restart in " + testPkg, 412 latchHolder[0].await(timeout, TimeUnit.MILLISECONDS)); 413 414 Thread.sleep(shortTimeout); 415 416 // Force-stop the service package, the test service should not be restarted. 417 latchHolder[0] = new CountDownLatch(2); 418 am.forceStopPackage(testPkg); 419 assertFalse("Test service should not be restarted in " + testPkg, 420 latchHolder[0].await(timeout * 2, TimeUnit.MILLISECONDS)); 421 } finally { 422 executeShellCmd("am service-restart-backoff enable " + testPkg); 423 mContext.unbindService(conn); 424 am.forceStopPackage(testPkg); 425 } 426 } 427 isPackageDependency(String pkgName, String libPackage)428 private boolean isPackageDependency(String pkgName, String libPackage) throws Exception { 429 final String output = SystemUtil.runShellCommand("dumpsys activity processes " + pkgName); 430 final Matcher matcher = Pattern.compile("packageDependencies=\\{.*?\\b" 431 + libPackage + "\\b.*?\\}").matcher(output); 432 return matcher.find(); 433 } 434 installPackage(String apkPath)435 private boolean installPackage(String apkPath) throws Exception { 436 return executeShellCmd("pm install -t " + apkPath).equals("Success\n"); 437 } 438 startServiceAndWait(String pkgName, MyUidImportanceListener uidListener, long timeout)439 private void startServiceAndWait(String pkgName, MyUidImportanceListener uidListener, 440 long timeout) throws Exception { 441 final Intent intent = new Intent(); 442 final ComponentName cn = ComponentName.unflattenFromString( 443 pkgName + "/" + TEST_SERVICE_NAME); 444 intent.setComponent(cn); 445 Log.i(TAG, "Starting service " + cn); 446 assertNotNull(mContext.startService(intent)); 447 assertTrue("Timed out to start service " + cn, 448 uidListener.waitFor(RunningAppProcessInfo.IMPORTANCE_SERVICE, timeout)); 449 } 450 killUidAndWait(ActivityManager am, int uid, MyUidImportanceListener uidListener, long timeout)451 private void killUidAndWait(ActivityManager am, int uid, MyUidImportanceListener uidListener, 452 long timeout) throws Exception { 453 am.killUid(uid, "test service restart"); 454 assertTrue("Timed out to kill " + uid, 455 uidListener.waitFor(RunningAppProcessInfo.IMPORTANCE_GONE, timeout)); 456 } 457 executeShellCmd(String cmd)458 private String executeShellCmd(String cmd) throws Exception { 459 final String result = SystemUtil.runShellCommand(mInstrumentation, cmd); 460 Log.d(TAG, String.format("Output for '%s': %s", cmd, result)); 461 return result; 462 } 463 setMemoryPressure(int pressure)464 private void setMemoryPressure(int pressure) throws Exception { 465 executeShellCmd("am memory-factor set " + MEMORY_PRESSURE_MAP[pressure]); 466 } 467 resetMemoryPressure()468 private void resetMemoryPressure() throws Exception { 469 executeShellCmd("am memory-factor reset"); 470 } 471 472 private static class MyUidImportanceListener implements OnUidImportanceListener { 473 final CountDownLatch[] mLatchHolder = new CountDownLatch[1]; 474 private final int mExpectedUid; 475 private int mExpectedImportance; 476 private int mCurrentImportance = RunningAppProcessInfo.IMPORTANCE_GONE; 477 long mCurrentTimestamp; 478 MyUidImportanceListener(int uid)479 MyUidImportanceListener(int uid) { 480 mExpectedUid = uid; 481 } 482 483 @Override onUidImportance(int uid, int importance)484 public void onUidImportance(int uid, int importance) { 485 if (uid == mExpectedUid) { 486 mCurrentTimestamp = SystemClock.uptimeMillis(); 487 synchronized (this) { 488 if (importance == mExpectedImportance && mLatchHolder[0] != null) { 489 mLatchHolder[0].countDown(); 490 } 491 mCurrentImportance = importance; 492 } 493 Log.i(TAG, "uid " + uid + " importance: " + importance); 494 } 495 } 496 waitFor(int expectedImportance, long timeout)497 boolean waitFor(int expectedImportance, long timeout) throws Exception { 498 synchronized (this) { 499 mExpectedImportance = expectedImportance; 500 if (mCurrentImportance == expectedImportance) { 501 return true; 502 } 503 mLatchHolder[0] = new CountDownLatch(1); 504 } 505 return mLatchHolder[0].await(timeout, TimeUnit.MILLISECONDS); 506 } 507 } 508 } 509