Merge "Fix rollbacks in multi-user case." into qt-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
fb1a20e4fb
@@ -862,6 +862,13 @@ public abstract class PackageManagerInternal {
|
|||||||
public static final String EXTRA_ENABLE_ROLLBACK_INSTALLED_USERS =
|
public static final String EXTRA_ENABLE_ROLLBACK_INSTALLED_USERS =
|
||||||
"android.content.pm.extra.ENABLE_ROLLBACK_INSTALLED_USERS";
|
"android.content.pm.extra.ENABLE_ROLLBACK_INSTALLED_USERS";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extra field name for the user id an install is associated with when
|
||||||
|
* enabling rollback.
|
||||||
|
*/
|
||||||
|
public static final String EXTRA_ENABLE_ROLLBACK_USER =
|
||||||
|
"android.content.pm.extra.ENABLE_ROLLBACK_USER";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used as the {@code enableRollbackCode} argument for
|
* Used as the {@code enableRollbackCode} argument for
|
||||||
* {@link PackageManagerInternal#setEnableRollbackCode} to indicate that
|
* {@link PackageManagerInternal#setEnableRollbackCode} to indicate that
|
||||||
|
|||||||
@@ -14913,6 +14913,9 @@ public class PackageManagerService extends IPackageManager.Stub
|
|||||||
enableRollbackIntent.putExtra(
|
enableRollbackIntent.putExtra(
|
||||||
PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_INSTALLED_USERS,
|
PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_INSTALLED_USERS,
|
||||||
installedUsers);
|
installedUsers);
|
||||||
|
enableRollbackIntent.putExtra(
|
||||||
|
PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_USER,
|
||||||
|
getUser().getIdentifier());
|
||||||
enableRollbackIntent.setDataAndType(Uri.fromFile(new File(origin.resolvedPath)),
|
enableRollbackIntent.setDataAndType(Uri.fromFile(new File(origin.resolvedPath)),
|
||||||
PACKAGE_MIME_TYPE);
|
PACKAGE_MIME_TYPE);
|
||||||
enableRollbackIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
enableRollbackIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ package com.android.server.rollback;
|
|||||||
|
|
||||||
import android.Manifest;
|
import android.Manifest;
|
||||||
import android.annotation.NonNull;
|
import android.annotation.NonNull;
|
||||||
|
import android.annotation.UserIdInt;
|
||||||
import android.app.AppOpsManager;
|
import android.app.AppOpsManager;
|
||||||
import android.content.BroadcastReceiver;
|
import android.content.BroadcastReceiver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
@@ -32,6 +33,7 @@ import android.content.pm.PackageManager;
|
|||||||
import android.content.pm.PackageManagerInternal;
|
import android.content.pm.PackageManagerInternal;
|
||||||
import android.content.pm.PackageParser;
|
import android.content.pm.PackageParser;
|
||||||
import android.content.pm.ParceledListSlice;
|
import android.content.pm.ParceledListSlice;
|
||||||
|
import android.content.pm.UserInfo;
|
||||||
import android.content.pm.VersionedPackage;
|
import android.content.pm.VersionedPackage;
|
||||||
import android.content.rollback.IRollbackManager;
|
import android.content.rollback.IRollbackManager;
|
||||||
import android.content.rollback.PackageRollbackInfo;
|
import android.content.rollback.PackageRollbackInfo;
|
||||||
@@ -43,6 +45,8 @@ import android.os.Handler;
|
|||||||
import android.os.HandlerThread;
|
import android.os.HandlerThread;
|
||||||
import android.os.ParcelFileDescriptor;
|
import android.os.ParcelFileDescriptor;
|
||||||
import android.os.Process;
|
import android.os.Process;
|
||||||
|
import android.os.UserHandle; // duped to avoid merge conflict
|
||||||
|
import android.os.UserManager; // out of order to avoid merge conflict
|
||||||
import android.os.SystemClock;
|
import android.os.SystemClock;
|
||||||
import android.os.UserHandle;
|
import android.os.UserHandle;
|
||||||
import android.provider.DeviceConfig;
|
import android.provider.DeviceConfig;
|
||||||
@@ -155,27 +159,12 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
|
|||||||
// expiration.
|
// expiration.
|
||||||
getHandler().post(() -> ensureRollbackDataLoaded());
|
getHandler().post(() -> ensureRollbackDataLoaded());
|
||||||
|
|
||||||
PackageInstaller packageInstaller = mContext.getPackageManager().getPackageInstaller();
|
// TODO: Make sure to register these call backs when a new user is
|
||||||
packageInstaller.registerSessionCallback(new SessionCallback(), getHandler());
|
// added too.
|
||||||
|
SessionCallback sessionCallback = new SessionCallback();
|
||||||
IntentFilter filter = new IntentFilter();
|
for (UserInfo userInfo : UserManager.get(mContext).getUsers(true)) {
|
||||||
filter.addAction(Intent.ACTION_PACKAGE_REPLACED);
|
registerUserCallbacks(userInfo.getUserHandle());
|
||||||
filter.addAction(Intent.ACTION_PACKAGE_FULLY_REMOVED);
|
}
|
||||||
filter.addDataScheme("package");
|
|
||||||
mContext.registerReceiver(new BroadcastReceiver() {
|
|
||||||
@Override
|
|
||||||
public void onReceive(Context context, Intent intent) {
|
|
||||||
String action = intent.getAction();
|
|
||||||
if (Intent.ACTION_PACKAGE_REPLACED.equals(action)) {
|
|
||||||
String packageName = intent.getData().getSchemeSpecificPart();
|
|
||||||
onPackageReplaced(packageName);
|
|
||||||
}
|
|
||||||
if (Intent.ACTION_PACKAGE_FULLY_REMOVED.equals(action)) {
|
|
||||||
String packageName = intent.getData().getSchemeSpecificPart();
|
|
||||||
onPackageFullyRemoved(packageName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, filter, null, getHandler());
|
|
||||||
|
|
||||||
IntentFilter enableRollbackFilter = new IntentFilter();
|
IntentFilter enableRollbackFilter = new IntentFilter();
|
||||||
enableRollbackFilter.addAction(Intent.ACTION_PACKAGE_ENABLE_ROLLBACK);
|
enableRollbackFilter.addAction(Intent.ACTION_PACKAGE_ENABLE_ROLLBACK);
|
||||||
@@ -195,11 +184,14 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
|
|||||||
PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_INSTALL_FLAGS, 0);
|
PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_INSTALL_FLAGS, 0);
|
||||||
int[] installedUsers = intent.getIntArrayExtra(
|
int[] installedUsers = intent.getIntArrayExtra(
|
||||||
PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_INSTALLED_USERS);
|
PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_INSTALLED_USERS);
|
||||||
|
int user = intent.getIntExtra(
|
||||||
|
PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_USER, 0);
|
||||||
|
|
||||||
File newPackageCodePath = new File(intent.getData().getPath());
|
File newPackageCodePath = new File(intent.getData().getPath());
|
||||||
|
|
||||||
getHandler().post(() -> {
|
getHandler().post(() -> {
|
||||||
boolean success = enableRollback(installFlags, newPackageCodePath,
|
boolean success = enableRollback(installFlags, newPackageCodePath,
|
||||||
installedUsers);
|
installedUsers, user);
|
||||||
int ret = PackageManagerInternal.ENABLE_ROLLBACK_SUCCEEDED;
|
int ret = PackageManagerInternal.ENABLE_ROLLBACK_SUCCEEDED;
|
||||||
if (!success) {
|
if (!success) {
|
||||||
ret = PackageManagerInternal.ENABLE_ROLLBACK_FAILED;
|
ret = PackageManagerInternal.ENABLE_ROLLBACK_FAILED;
|
||||||
@@ -221,6 +213,39 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
|
|||||||
registerTimeChangeReceiver();
|
registerTimeChangeReceiver();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void registerUserCallbacks(UserHandle user) {
|
||||||
|
Context context = getContextAsUser(user);
|
||||||
|
if (context == null) {
|
||||||
|
Log.e(TAG, "Unable to register user callbacks for user " + user);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Reuse the same SessionCallback and broadcast receiver
|
||||||
|
// instances, rather than creating new instances for each user.
|
||||||
|
|
||||||
|
context.getPackageManager().getPackageInstaller()
|
||||||
|
.registerSessionCallback(new SessionCallback(), getHandler());
|
||||||
|
|
||||||
|
IntentFilter filter = new IntentFilter();
|
||||||
|
filter.addAction(Intent.ACTION_PACKAGE_REPLACED);
|
||||||
|
filter.addAction(Intent.ACTION_PACKAGE_FULLY_REMOVED);
|
||||||
|
filter.addDataScheme("package");
|
||||||
|
context.registerReceiver(new BroadcastReceiver() {
|
||||||
|
@Override
|
||||||
|
public void onReceive(Context context, Intent intent) {
|
||||||
|
String action = intent.getAction();
|
||||||
|
if (Intent.ACTION_PACKAGE_REPLACED.equals(action)) {
|
||||||
|
String packageName = intent.getData().getSchemeSpecificPart();
|
||||||
|
onPackageReplaced(packageName);
|
||||||
|
}
|
||||||
|
if (Intent.ACTION_PACKAGE_FULLY_REMOVED.equals(action)) {
|
||||||
|
String packageName = intent.getData().getSchemeSpecificPart();
|
||||||
|
onPackageFullyRemoved(packageName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, filter, null, getHandler());
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ParceledListSlice getAvailableRollbacks() {
|
public ParceledListSlice getAvailableRollbacks() {
|
||||||
enforceManageRollbacks("getAvailableRollbacks");
|
enforceManageRollbacks("getAvailableRollbacks");
|
||||||
@@ -781,6 +806,14 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Context getContextAsUser(UserHandle user) {
|
||||||
|
try {
|
||||||
|
return mContext.createPackageContextAsUser(mContext.getPackageName(), 0, user);
|
||||||
|
} catch (PackageManager.NameNotFoundException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called via broadcast by the package manager when a package is being
|
* Called via broadcast by the package manager when a package is being
|
||||||
* staged for install with rollback enabled. Called before the package has
|
* staged for install with rollback enabled. Called before the package has
|
||||||
@@ -789,10 +822,11 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
|
|||||||
* @param installFlags information about what is being installed.
|
* @param installFlags information about what is being installed.
|
||||||
* @param newPackageCodePath path to the package about to be installed.
|
* @param newPackageCodePath path to the package about to be installed.
|
||||||
* @param installedUsers the set of users for which a given package is installed.
|
* @param installedUsers the set of users for which a given package is installed.
|
||||||
|
* @param user the user that owns the install session to enable rollback on.
|
||||||
* @return true if enabling the rollback succeeds, false otherwise.
|
* @return true if enabling the rollback succeeds, false otherwise.
|
||||||
*/
|
*/
|
||||||
private boolean enableRollback(int installFlags, File newPackageCodePath,
|
private boolean enableRollback(int installFlags, File newPackageCodePath,
|
||||||
int[] installedUsers) {
|
int[] installedUsers, @UserIdInt int user) {
|
||||||
|
|
||||||
// Find the session id associated with this install.
|
// Find the session id associated with this install.
|
||||||
// TODO: It would be nice if package manager or package installer told
|
// TODO: It would be nice if package manager or package installer told
|
||||||
@@ -800,8 +834,17 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
|
|||||||
// ourselves.
|
// ourselves.
|
||||||
PackageInstaller.SessionInfo session = null;
|
PackageInstaller.SessionInfo session = null;
|
||||||
|
|
||||||
|
// getAllSessions only returns sessions for the associated user.
|
||||||
|
// Create a context with the right user so we can find the matching
|
||||||
|
// session.
|
||||||
|
final Context context = getContextAsUser(UserHandle.of(user));
|
||||||
|
if (context == null) {
|
||||||
|
Log.e(TAG, "Unable to create context for install session user.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
int parentSessionId = -1;
|
int parentSessionId = -1;
|
||||||
PackageInstaller installer = mContext.getPackageManager().getPackageInstaller();
|
PackageInstaller installer = context.getPackageManager().getPackageInstaller();
|
||||||
for (PackageInstaller.SessionInfo info : installer.getAllSessions()) {
|
for (PackageInstaller.SessionInfo info : installer.getAllSessions()) {
|
||||||
if (info.isMultiPackage()) {
|
if (info.isMultiPackage()) {
|
||||||
for (int childId : info.getChildSessionIds()) {
|
for (int childId : info.getChildSessionIds()) {
|
||||||
@@ -918,7 +961,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
|
|||||||
PackageManager pm = mContext.getPackageManager();
|
PackageManager pm = mContext.getPackageManager();
|
||||||
final PackageInfo pkgInfo;
|
final PackageInfo pkgInfo;
|
||||||
try {
|
try {
|
||||||
pkgInfo = pm.getPackageInfo(packageName, isApex ? PackageManager.MATCH_APEX : 0);
|
pkgInfo = getPackageInfo(packageName);
|
||||||
} catch (PackageManager.NameNotFoundException e) {
|
} catch (PackageManager.NameNotFoundException e) {
|
||||||
// TODO: Support rolling back fresh package installs rather than
|
// TODO: Support rolling back fresh package installs rather than
|
||||||
// fail here. Test this case.
|
// fail here. Test this case.
|
||||||
@@ -1154,7 +1197,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
|
|||||||
PackageManager pm = mContext.getPackageManager();
|
PackageManager pm = mContext.getPackageManager();
|
||||||
PackageInfo pkgInfo = null;
|
PackageInfo pkgInfo = null;
|
||||||
try {
|
try {
|
||||||
pkgInfo = pm.getPackageInfo(packageName, PackageManager.MATCH_APEX);
|
pkgInfo = getPackageInfo(packageName);
|
||||||
} catch (PackageManager.NameNotFoundException e) {
|
} catch (PackageManager.NameNotFoundException e) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -1162,6 +1205,26 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
|
|||||||
return new VersionedPackage(packageName, pkgInfo.getLongVersionCode());
|
return new VersionedPackage(packageName, pkgInfo.getLongVersionCode());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets PackageInfo for the given package.
|
||||||
|
* Matches any user and apex. Returns null if no such package is
|
||||||
|
* installed.
|
||||||
|
*/
|
||||||
|
private PackageInfo getPackageInfo(String packageName)
|
||||||
|
throws PackageManager.NameNotFoundException {
|
||||||
|
PackageManager pm = mContext.getPackageManager();
|
||||||
|
try {
|
||||||
|
// The MATCH_ANY_USER flag doesn't mix well with the MATCH_APEX
|
||||||
|
// flag, so make two separate attempts to get the package info.
|
||||||
|
// We don't need both flags at the same time because we assume
|
||||||
|
// apex files are always installed for all users.
|
||||||
|
return pm.getPackageInfo(packageName, PackageManager.MATCH_ANY_USER);
|
||||||
|
} catch (PackageManager.NameNotFoundException e) {
|
||||||
|
return pm.getPackageInfo(packageName, PackageManager.MATCH_APEX);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private boolean packageVersionsEqual(VersionedPackage a, VersionedPackage b) {
|
private boolean packageVersionsEqual(VersionedPackage a, VersionedPackage b) {
|
||||||
return a.getPackageName().equals(b.getPackageName())
|
return a.getPackageName().equals(b.getPackageName())
|
||||||
&& a.getLongVersionCode() == b.getLongVersionCode();
|
&& a.getLongVersionCode() == b.getLongVersionCode();
|
||||||
|
|||||||
Reference in New Issue
Block a user