Fix null RollbackManager in RollbackHealthObserver and minor todos
1. RollbackManager was instantiated by Context#getSystemService in RollbackHealthObserver. At this time, RollbackManager has not yet been published as a service to the system, so RollbackManager was null. We now #getSystemService lazily so RollbackManager is never null. 2. Pass causePackages from RollbackHealthObserver to RollbackManager 3. Also fixed flaky ignored test exercising PackageWatchdog auto rollback Test: atest RollbackTest Bug: 123615508 112431924 Change-Id: I8f15c257b1efd96a96656405d3d7f74576a32c8e
This commit is contained in:
@@ -19,6 +19,7 @@ package com.android.server.rollback;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageInstaller;
|
||||
import android.content.pm.VersionedPackage;
|
||||
import android.content.rollback.PackageRollbackInfo;
|
||||
import android.content.rollback.RollbackInfo;
|
||||
import android.content.rollback.RollbackManager;
|
||||
@@ -41,12 +42,10 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve
|
||||
private static final String TAG = "RollbackPackageHealthObserver";
|
||||
private static final String NAME = "rollback-observer";
|
||||
private Context mContext;
|
||||
private RollbackManager mRollbackManager;
|
||||
private Handler mHandler;
|
||||
|
||||
RollbackPackageHealthObserver(Context context) {
|
||||
mContext = context;
|
||||
mRollbackManager = mContext.getSystemService(RollbackManager.class);
|
||||
HandlerThread handlerThread = new HandlerThread("RollbackPackageHealthObserver");
|
||||
handlerThread.start();
|
||||
mHandler = handlerThread.getThreadHandler();
|
||||
@@ -55,7 +54,9 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve
|
||||
|
||||
@Override
|
||||
public int onHealthCheckFailed(String packageName, long versionCode) {
|
||||
RollbackInfo rollback = getAvailableRollback(packageName, versionCode);
|
||||
RollbackInfo rollback =
|
||||
getAvailableRollback(mContext.getSystemService(RollbackManager.class),
|
||||
packageName, versionCode);
|
||||
if (rollback == null) {
|
||||
// Don't handle the notification, no rollbacks available for the package
|
||||
return PackageHealthObserverImpact.USER_IMPACT_NONE;
|
||||
@@ -66,7 +67,8 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve
|
||||
|
||||
@Override
|
||||
public boolean execute(String packageName, long versionCode) {
|
||||
RollbackInfo rollback = getAvailableRollback(packageName, versionCode);
|
||||
RollbackManager rollbackManager = mContext.getSystemService(RollbackManager.class);
|
||||
RollbackInfo rollback = getAvailableRollback(rollbackManager, packageName, versionCode);
|
||||
if (rollback == null) {
|
||||
// Expected a rollback to be available, what happened?
|
||||
return false;
|
||||
@@ -86,12 +88,9 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve
|
||||
});
|
||||
|
||||
// TODO(zezeozue): Log initiated metrics
|
||||
// TODO: Pass the package as a cause package instead of using
|
||||
// Collections.emptyList once the version of the failing package is
|
||||
// easily available.
|
||||
mHandler.post(() ->
|
||||
mRollbackManager.commitRollback(rollback.getRollbackId(),
|
||||
Collections.emptyList(),
|
||||
rollbackManager.commitRollback(rollback.getRollbackId(),
|
||||
Collections.singletonList(new VersionedPackage(packageName, versionCode)),
|
||||
rollbackReceiver.getIntentSender()));
|
||||
// Assume rollback executed successfully
|
||||
return true;
|
||||
@@ -110,8 +109,9 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve
|
||||
PackageWatchdog.getInstance(mContext).startObservingHealth(this, packages, durationMs);
|
||||
}
|
||||
|
||||
private RollbackInfo getAvailableRollback(String packageName, long versionCode) {
|
||||
for (RollbackInfo rollback : mRollbackManager.getAvailableRollbacks()) {
|
||||
private RollbackInfo getAvailableRollback(RollbackManager rollbackManager,
|
||||
String packageName, long versionCode) {
|
||||
for (RollbackInfo rollback : rollbackManager.getAvailableRollbacks()) {
|
||||
for (PackageRollbackInfo packageRollback : rollback.getPackages()) {
|
||||
if (packageName.equals(packageRollback.getPackageName())
|
||||
&& packageRollback.getVersionRolledBackFrom().getVersionCode()
|
||||
|
||||
@@ -17,17 +17,30 @@
|
||||
package com.android.tests.rollback.testapp;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
|
||||
/**
|
||||
* A crashing test app for testing apk rollback support.
|
||||
*/
|
||||
public class CrashingMainActivity extends Activity {
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
incrementCountAndBroadcast();
|
||||
throw new RuntimeException("Intended force crash");
|
||||
}
|
||||
|
||||
public void incrementCountAndBroadcast() {
|
||||
SharedPreferences preferences = getSharedPreferences("prefs", Context.MODE_PRIVATE);
|
||||
SharedPreferences.Editor editor = preferences.edit();
|
||||
int count = preferences.getInt("crash_count", 0);
|
||||
editor.putInt("crash_count", ++count).commit();
|
||||
|
||||
Intent intent = new Intent("com.android.tests.rollback.CRASH");
|
||||
intent.putExtra("count", count);
|
||||
sendBroadcast(intent);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package com.android.tests.rollback;
|
||||
|
||||
import android.Manifest;
|
||||
import android.app.ActivityManager;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
@@ -36,7 +37,6 @@ import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
@@ -45,6 +45,7 @@ import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.SynchronousQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
@@ -413,7 +414,6 @@ public class RollbackTest {
|
||||
|
||||
/**
|
||||
* Test that app user data is rolled back.
|
||||
* TODO: Stop ignoring this test once user data rollback is supported.
|
||||
*/
|
||||
@Test
|
||||
public void testUserDataRollback() throws Exception {
|
||||
@@ -568,9 +568,7 @@ public class RollbackTest {
|
||||
}
|
||||
|
||||
/**
|
||||
* Test rollback of multi-package installs.
|
||||
* TODO: Stop ignoring this test once support for multi-package rollback
|
||||
* is implemented.
|
||||
* Test rollback of multi-package installs is implemented.
|
||||
*/
|
||||
@Test
|
||||
public void testMultiPackage() throws Exception {
|
||||
@@ -630,18 +628,20 @@ public class RollbackTest {
|
||||
assertEquals(versionRolledBackTo, info.getVersionRolledBackTo().getLongVersionCode());
|
||||
}
|
||||
|
||||
// TODO(zezeozue): Stop ignoring after fixing race between rolling back and testing version
|
||||
/**
|
||||
* Test bad update automatic rollback.
|
||||
*/
|
||||
@Ignore("Flaky")
|
||||
@Test
|
||||
public void testBadUpdateRollback() throws Exception {
|
||||
BroadcastReceiver crashCountReceiver = null;
|
||||
Context context = InstrumentationRegistry.getContext();
|
||||
try {
|
||||
RollbackTestUtils.adoptShellPermissionIdentity(
|
||||
Manifest.permission.INSTALL_PACKAGES,
|
||||
Manifest.permission.DELETE_PACKAGES,
|
||||
Manifest.permission.MANAGE_ROLLBACKS);
|
||||
Manifest.permission.MANAGE_ROLLBACKS,
|
||||
Manifest.permission.KILL_BACKGROUND_PROCESSES,
|
||||
Manifest.permission.RESTART_PACKAGES);
|
||||
RollbackManager rm = RollbackTestUtils.getRollbackManager();
|
||||
|
||||
// Prep installation of the test apps.
|
||||
@@ -669,23 +669,52 @@ public class RollbackTest {
|
||||
rm.getAvailableRollbacks(), TEST_APP_B);
|
||||
assertRollbackInfoEquals(TEST_APP_B, 2, 1, rollbackB);
|
||||
|
||||
BlockingQueue<Integer> crashQueue = new SynchronousQueue<>();
|
||||
|
||||
IntentFilter crashCountFilter = new IntentFilter();
|
||||
crashCountFilter.addAction("com.android.tests.rollback.CRASH");
|
||||
crashCountFilter.addCategory(Intent.CATEGORY_DEFAULT);
|
||||
|
||||
crashCountReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
try {
|
||||
// Sleep long enough for packagewatchdog to be notified of crash
|
||||
Thread.sleep(1000);
|
||||
// Kill app and close AppErrorDialog
|
||||
ActivityManager am = context.getSystemService(ActivityManager.class);
|
||||
am.killBackgroundProcesses(TEST_APP_A);
|
||||
// Allow another package launch
|
||||
crashQueue.offer(intent.getIntExtra("count", 0), 5, TimeUnit.SECONDS);
|
||||
} catch (InterruptedException e) {
|
||||
fail("Failed to communicate with test app");
|
||||
}
|
||||
}
|
||||
};
|
||||
context.registerReceiver(crashCountReceiver, crashCountFilter);
|
||||
|
||||
// Start apps PackageWatchdog#TRIGGER_FAILURE_COUNT times so TEST_APP_A crashes
|
||||
for (int i = 0; i < 5; i++) {
|
||||
Integer crashCount = null;
|
||||
do {
|
||||
RollbackTestUtils.launchPackage(TEST_APP_A);
|
||||
Thread.sleep(1000);
|
||||
}
|
||||
Thread.sleep(1000);
|
||||
crashCount = crashQueue.poll(5, TimeUnit.SECONDS);
|
||||
if (crashCount == null) {
|
||||
fail("Timed out waiting for crash signal from test app");
|
||||
}
|
||||
} while(crashCount < 5);
|
||||
|
||||
// TEST_APP_A is automatically rolled back by the RollbackPackageHealthObserver
|
||||
assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
|
||||
// Instrumented app is still the package installer
|
||||
Context context = InstrumentationRegistry.getContext();
|
||||
String installer = context.getPackageManager().getInstallerPackageName(TEST_APP_A);
|
||||
assertEquals(INSTRUMENTED_APP, installer);
|
||||
// TEST_APP_B is untouched
|
||||
assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_B));
|
||||
} finally {
|
||||
RollbackTestUtils.dropShellPermissionIdentity();
|
||||
if (crashCountReceiver != null) {
|
||||
context.unregisterReceiver(crashCountReceiver);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user