Add RollbackManagerInternal (4/n)
This is an effort to modularize RollbackManager.
AIDL interfaces (IRollbackManager in this case) can’t be used across
module boundaries. We need to add a wrapper so system_server classes
can depend on this wrapper instead of IRollbackManager.
See https://docs.google.com/document/d/1d60nWwTcwrLps8dWDkxtkcUxSNt6q1x9rgAKwG-xO9E/view#heading=h.vqwoptkbpscx
for more details.
Bug: 150347230
Test: atest StagedRollbackTest
Change-Id: Ie34489aa3276f75d192ac4a08112012ef7f94509
diff --git a/core/java/android/os/UserHandle.java b/core/java/android/os/UserHandle.java
index b92fb47..38ba47a 100644
--- a/core/java/android/os/UserHandle.java
+++ b/core/java/android/os/UserHandle.java
@@ -24,6 +24,8 @@
import android.compat.annotation.UnsupportedAppUsage;
import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
/**
* Representation of a user on the device.
@@ -257,6 +259,26 @@
}
/** @hide */
+ @NonNull
+ public static int[] fromUserHandles(@NonNull List<UserHandle> users) {
+ int[] userIds = new int[users.size()];
+ for (int i = 0; i < userIds.length; ++i) {
+ userIds[i] = users.get(i).getIdentifier();
+ }
+ return userIds;
+ }
+
+ /** @hide */
+ @NonNull
+ public static List<UserHandle> toUserHandles(@NonNull int[] userIds) {
+ List<UserHandle> users = new ArrayList<>(userIds.length);
+ for (int i = 0; i < userIds.length; ++i) {
+ users.add(UserHandle.of(userIds[i]));
+ }
+ return users;
+ }
+
+ /** @hide */
@TestApi
@SystemApi
public static UserHandle of(@UserIdInt int userId) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 7459042..69318d2 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -236,7 +236,6 @@
import android.content.pm.parsing.result.ParseResult;
import android.content.pm.parsing.result.ParseTypeImpl;
import android.content.res.Resources;
-import android.content.rollback.IRollbackManager;
import android.database.ContentObserver;
import android.graphics.Bitmap;
import android.hardware.display.DisplayManager;
@@ -367,6 +366,7 @@
import com.android.server.pm.permission.PermissionManagerServiceInternal;
import com.android.server.pm.permission.PermissionsState;
import com.android.server.policy.PermissionPolicyInternal;
+import com.android.server.rollback.RollbackManagerInternal;
import com.android.server.security.VerityUtils;
import com.android.server.storage.DeviceStorageMonitorInternal;
import com.android.server.utils.TimingsTraceAndSlog;
@@ -14314,8 +14314,7 @@
*/
private boolean performRollbackManagerRestore(int userId, int token, PackageInstalledInfo res,
PostInstallData data) {
- IRollbackManager rm = IRollbackManager.Stub.asInterface(
- ServiceManager.getService(Context.ROLLBACK_SERVICE));
+ RollbackManagerInternal rm = LocalServices.getService(RollbackManagerInternal.class);
final String packageName = res.pkg.getPackageName();
final int[] allUsers = mUserManager.getUserIds();
@@ -14343,9 +14342,9 @@
if (ps != null && doSnapshotOrRestore) {
final String seInfo = AndroidPackageUtils.getSeInfo(res.pkg, ps);
try {
- rm.snapshotAndRestoreUserData(packageName, installedUsers, appId, ceDataInode,
- seInfo, token);
- } catch (RemoteException re) {
+ rm.snapshotAndRestoreUserData(packageName, UserHandle.toUserHandles(installedUsers),
+ appId, ceDataInode, seInfo, token);
+ } catch (RuntimeException re) {
Log.e(TAG, "Error snapshotting/restoring user data: " + re);
return false;
}
@@ -21390,7 +21389,7 @@
public void onShellCommand(FileDescriptor in, FileDescriptor out,
FileDescriptor err, String[] args, ShellCallback callback,
ResultReceiver resultReceiver) {
- (new PackageManagerShellCommand(this, mPermissionManagerService)).exec(
+ (new PackageManagerShellCommand(this, mPermissionManagerService, mContext)).exec(
this, in, out, err, args, callback, resultReceiver);
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index ca68e31..d06a231 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -66,7 +66,6 @@
import android.content.pm.parsing.result.ParseTypeImpl;
import android.content.res.AssetManager;
import android.content.res.Resources;
-import android.content.rollback.IRollbackManager;
import android.content.rollback.PackageRollbackInfo;
import android.content.rollback.RollbackInfo;
import android.content.rollback.RollbackManager;
@@ -145,6 +144,7 @@
final IPackageManager mInterface;
final IPermissionManager mPermissionManager;
+ final Context mShellPackageContext;
final private WeakHashMap<String, Resources> mResourceCache =
new WeakHashMap<String, Resources>();
int mTargetUser;
@@ -153,9 +153,15 @@
int mQueryFlags;
PackageManagerShellCommand(
- PackageManagerService service, IPermissionManager permissionManager) {
+ PackageManagerService service, IPermissionManager permissionManager, Context context) {
mInterface = service;
mPermissionManager = permissionManager;
+ try {
+ mShellPackageContext = context.createPackageContext("com.android.shell", 0);
+ } catch (NameNotFoundException e) {
+ // should not happen
+ throw new RuntimeException(e);
+ }
}
@Override
@@ -460,32 +466,25 @@
}
final LocalIntentReceiver receiver = new LocalIntentReceiver();
- try {
- IRollbackManager rm = IRollbackManager.Stub.asInterface(
- ServiceManager.getService(Context.ROLLBACK_SERVICE));
-
- RollbackInfo rollback = null;
- for (RollbackInfo r : (List<RollbackInfo>) rm.getAvailableRollbacks().getList()) {
- for (PackageRollbackInfo info : r.getPackages()) {
- if (packageName.equals(info.getPackageName())) {
- rollback = r;
- break;
- }
+ RollbackManager rm = mShellPackageContext.getSystemService(RollbackManager.class);
+ RollbackInfo rollback = null;
+ for (RollbackInfo r : rm.getAvailableRollbacks()) {
+ for (PackageRollbackInfo info : r.getPackages()) {
+ if (packageName.equals(info.getPackageName())) {
+ rollback = r;
+ break;
}
}
-
- if (rollback == null) {
- pw.println("No available rollbacks for: " + packageName);
- return 1;
- }
-
- rm.commitRollback(rollback.getRollbackId(),
- ParceledListSlice.<VersionedPackage>emptyList(),
- "com.android.shell", receiver.getIntentSender());
- } catch (RemoteException re) {
- // Cannot happen.
}
+ if (rollback == null) {
+ pw.println("No available rollbacks for: " + packageName);
+ return 1;
+ }
+
+ rm.commitRollback(rollback.getRollbackId(),
+ Collections.emptyList(), receiver.getIntentSender());
+
final Intent result = receiver.getResult();
final int status = result.getIntExtra(RollbackManager.EXTRA_STATUS,
RollbackManager.STATUS_FAILURE);
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index 9d81928..0ead1327 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -40,7 +40,6 @@
import android.content.pm.PackageParser.SigningDetails.SignatureSchemeVersion;
import android.content.pm.ParceledListSlice;
import android.content.pm.parsing.PackageInfoWithoutStateUtils;
-import android.content.rollback.IRollbackManager;
import android.content.rollback.RollbackInfo;
import android.content.rollback.RollbackManager;
import android.os.Bundle;
@@ -52,7 +51,6 @@
import android.os.ParcelableException;
import android.os.PowerManager;
import android.os.RemoteException;
-import android.os.ServiceManager;
import android.os.UserHandle;
import android.os.UserManagerInternal;
import android.os.storage.IStorageManager;
@@ -75,6 +73,7 @@
import com.android.server.pm.parsing.pkg.AndroidPackage;
import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
import com.android.server.pm.parsing.pkg.ParsedPackage;
+import com.android.server.rollback.RollbackManagerInternal;
import com.android.server.rollback.WatchdogRollbackLogger;
import java.io.File;
@@ -483,8 +482,7 @@
final UserManagerInternal um = LocalServices.getService(UserManagerInternal.class);
final int[] allUsers = um.getUserIds();
- IRollbackManager rm = IRollbackManager.Stub.asInterface(
- ServiceManager.getService(Context.ROLLBACK_SERVICE));
+ RollbackManagerInternal rm = LocalServices.getService(RollbackManagerInternal.class);
for (int i = 0, sessionsSize = apexSessions.size(); i < sessionsSize; i++) {
final String packageName = apexSessions.get(i).getPackageName();
@@ -500,18 +498,18 @@
}
private void snapshotAndRestoreApexUserData(
- String packageName, int[] allUsers, IRollbackManager rm) {
+ String packageName, int[] allUsers, RollbackManagerInternal rm) {
try {
// appId, ceDataInode, and seInfo are not needed for APEXes
- rm.snapshotAndRestoreUserData(packageName, allUsers, 0, 0,
+ rm.snapshotAndRestoreUserData(packageName, UserHandle.toUserHandles(allUsers), 0, 0,
null, 0 /*token*/);
- } catch (RemoteException re) {
+ } catch (RuntimeException re) {
Slog.e(TAG, "Error snapshotting/restoring user data: " + re);
}
}
private void snapshotAndRestoreApkInApexUserData(
- String packageName, int[] allUsers, IRollbackManager rm) {
+ String packageName, int[] allUsers, RollbackManagerInternal rm) {
PackageManagerInternal mPmi = LocalServices.getService(PackageManagerInternal.class);
AndroidPackage pkg = mPmi.getPackage(packageName);
if (pkg == null) {
@@ -532,9 +530,9 @@
final String seInfo = AndroidPackageUtils.getSeInfo(pkg, ps);
try {
- rm.snapshotAndRestoreUserData(packageName, installedUsers, appId, ceDataInode,
- seInfo, 0 /*token*/);
- } catch (RemoteException re) {
+ rm.snapshotAndRestoreUserData(packageName, UserHandle.toUserHandles(installedUsers),
+ appId, ceDataInode, seInfo, 0 /*token*/);
+ } catch (RuntimeException re) {
Slog.e(TAG, "Error snapshotting/restoring user data: " + re);
}
}
@@ -878,11 +876,11 @@
if ((apksToInstall.params.installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) != 0) {
// If rollback is available for this session, notify the rollback
// manager of the apk session so it can properly enable rollback.
- final IRollbackManager rm = IRollbackManager.Stub.asInterface(
- ServiceManager.getService(Context.ROLLBACK_SERVICE));
+ final RollbackManagerInternal rm =
+ LocalServices.getService(RollbackManagerInternal.class);
try {
rm.notifyStagedApkSession(session.sessionId, apksToInstall.sessionId);
- } catch (RemoteException re) {
+ } catch (RuntimeException re) {
Slog.e(TAG, "Failed to notifyStagedApkSession for session: "
+ session.sessionId, re);
}
@@ -1384,8 +1382,8 @@
// If rollback is enabled for this session, we call through to the RollbackManager
// with the list of sessions it must enable rollback for. Note that
// notifyStagedSession is a synchronous operation.
- final IRollbackManager rm = IRollbackManager.Stub.asInterface(
- ServiceManager.getService(Context.ROLLBACK_SERVICE));
+ final RollbackManagerInternal rm =
+ LocalServices.getService(RollbackManagerInternal.class);
try {
// NOTE: To stay consistent with the non-staged install flow, we don't fail the
// entire install if rollbacks can't be enabled.
@@ -1395,7 +1393,7 @@
mSessionRollbackIds.put(session.sessionId, rollbackId);
}
}
- } catch (RemoteException re) {
+ } catch (RuntimeException re) {
Slog.e(TAG, "Failed to notifyStagedSession for session: "
+ session.sessionId, re);
}
diff --git a/services/core/java/com/android/server/rollback/RollbackManagerInternal.java b/services/core/java/com/android/server/rollback/RollbackManagerInternal.java
new file mode 100644
index 0000000..b473b8c
--- /dev/null
+++ b/services/core/java/com/android/server/rollback/RollbackManagerInternal.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.rollback;
+
+import android.annotation.NonNull;
+import android.os.UserHandle;
+
+import java.util.List;
+
+/**
+ * A partial interface of IRollbackManager used by the system server only.
+ *
+ * @hide
+ */
+public interface RollbackManagerInternal {
+ /**
+ * Exposed for use from the system server only. Callback from the package
+ * manager during the install flow when user data can be backed up and restored for a given
+ * package.
+ *
+ * @param packageName Name of the package to restore/backup user data for
+ * @param users Users whose data to be restored/backed up
+ * @param appId ID of the package to restore/backup user data for
+ * @param ceDataInode The index node of CE data to restore/backup
+ * @param seInfo The seinfo tag used by SELinux policy
+ * @param token Used to inform the package manager that the pending package install is finished
+ */
+ void snapshotAndRestoreUserData(@NonNull String packageName, @NonNull List<UserHandle> users,
+ int appId, long ceDataInode, @NonNull String seInfo, int token);
+
+ /**
+ * Used by the staging manager to notify the RollbackManager that a session is
+ * being staged. In the case of multi-package sessions, the specified sessionId
+ * is that of the parent session.
+ *
+ * NOTE: This call is synchronous.
+ *
+ * @param sessionId The session ID that is being staged
+ * @return The rollback id if rollback was enabled successfully, or -1 if not.
+ */
+ int notifyStagedSession(int sessionId);
+
+ /**
+ * Used by the staging manager to notify the RollbackManager of the apk
+ * session for a staged session.
+ *
+ * @param originalSessionId The original session ID where this apk session belongs
+ * @param apkSessionId The ID of this apk session
+ */
+ void notifyStagedApkSession(int originalSessionId, int apkSessionId);
+}
diff --git a/services/core/java/com/android/server/rollback/RollbackManagerService.java b/services/core/java/com/android/server/rollback/RollbackManagerService.java
index f7ba9bb..a2c66a4 100644
--- a/services/core/java/com/android/server/rollback/RollbackManagerService.java
+++ b/services/core/java/com/android/server/rollback/RollbackManagerService.java
@@ -18,6 +18,7 @@
import android.content.Context;
+import com.android.server.LocalServices;
import com.android.server.SystemService;
/**
@@ -38,6 +39,7 @@
public void onStart() {
mService = new RollbackManagerServiceImpl(getContext());
publishBinderService(Context.ROLLBACK_SERVICE, mService);
+ LocalServices.addService(RollbackManagerInternal.class, mService);
}
@Override
diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
index e592053..b33e04c3 100644
--- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
+++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
@@ -118,7 +118,7 @@
* mutually-exclusive to ensure @WorkerThread methods and @ExtThread ones never call into each
* other.
*/
-class RollbackManagerServiceImpl extends IRollbackManager.Stub {
+class RollbackManagerServiceImpl extends IRollbackManager.Stub implements RollbackManagerInternal {
/**
* Denotes that the annotated methods is intended for external entities and should be called on
* an external thread. By 'external' we mean any thread that is not the handler thread.
@@ -927,6 +927,15 @@
@ExtThread
@Override
+ public void snapshotAndRestoreUserData(String packageName, List<UserHandle> users, int appId,
+ long ceDataInode, String seInfo, int token) {
+ assertNotInWorkerThread();
+ snapshotAndRestoreUserData(packageName, UserHandle.fromUserHandles(users), appId,
+ ceDataInode, seInfo, token);
+ }
+
+ @ExtThread
+ @Override
public void snapshotAndRestoreUserData(String packageName, int[] userIds, int appId,
long ceDataInode, String seInfo, int token) {
assertNotInWorkerThread();