From 536691805cd94c8b7e819074ee523b0d4016c14d Mon Sep 17 00:00:00 2001 From: JW Wang Date: Thu, 27 Feb 2020 15:25:09 +0800 Subject: [PATCH] Add RollbackManagerInternal (4/n) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- core/java/android/os/UserHandle.java | 22 +++++++ .../server/pm/PackageManagerService.java | 13 ++-- .../server/pm/PackageManagerShellCommand.java | 47 +++++++------- .../com/android/server/pm/StagingManager.java | 32 +++++---- .../rollback/RollbackManagerInternal.java | 65 +++++++++++++++++++ .../rollback/RollbackManagerService.java | 2 + .../rollback/RollbackManagerServiceImpl.java | 11 +++- 7 files changed, 143 insertions(+), 49 deletions(-) create mode 100644 services/core/java/com/android/server/rollback/RollbackManagerInternal.java diff --git a/core/java/android/os/UserHandle.java b/core/java/android/os/UserHandle.java index b92fb47d11128..38ba47ab37018 100644 --- a/core/java/android/os/UserHandle.java +++ b/core/java/android/os/UserHandle.java @@ -24,6 +24,8 @@ import android.annotation.UserIdInt; import android.compat.annotation.UnsupportedAppUsage; import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.List; /** * Representation of a user on the device. @@ -256,6 +258,26 @@ public final class UserHandle implements Parcelable { return getAppId(Binder.getCallingUid()); } + /** @hide */ + @NonNull + public static int[] fromUserHandles(@NonNull List 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 toUserHandles(@NonNull int[] userIds) { + List users = new ArrayList<>(userIds.length); + for (int i = 0; i < userIds.length; ++i) { + users.add(UserHandle.of(userIds[i])); + } + return users; + } + /** @hide */ @TestApi @SystemApi diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 74590424d5be2..69318d278d9fc 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.component.ParsedService; 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.PermissionManagerService; 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 @@ public class PackageManagerService extends IPackageManager.Stub */ 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 @@ public class PackageManagerService extends IPackageManager.Stub 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 class PackageManagerService extends IPackageManager.Stub 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 ca68e31e03a1d..d06a231d1da68 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.ParseResult; 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 @@ class PackageManagerShellCommand extends ShellCommand { final IPackageManager mInterface; final IPermissionManager mPermissionManager; + final Context mShellPackageContext; final private WeakHashMap mResourceCache = new WeakHashMap(); int mTargetUser; @@ -153,9 +153,15 @@ class PackageManagerShellCommand extends ShellCommand { 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 @@ class PackageManagerShellCommand extends ShellCommand { } final LocalIntentReceiver receiver = new LocalIntentReceiver(); - try { - IRollbackManager rm = IRollbackManager.Stub.asInterface( - ServiceManager.getService(Context.ROLLBACK_SERVICE)); - - RollbackInfo rollback = null; - for (RollbackInfo r : (List) 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.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 9d819282e4a0c..0ead13276f192 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; 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.ParcelFileDescriptor; 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.PackageParser2; 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 @@ public class StagingManager { 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 @@ public class StagingManager { } 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 @@ public class StagingManager { 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 @@ public class StagingManager { 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 @@ public class StagingManager { // 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 @@ public class StagingManager { 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 0000000000000..b473b8ca9859f --- /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 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 f7ba9bbc695f7..a2c66a40a640e 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 @@ package com.android.server.rollback; import android.content.Context; +import com.android.server.LocalServices; import com.android.server.SystemService; /** @@ -38,6 +39,7 @@ public final class RollbackManagerService extends SystemService { 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 e592053e21deb..b33e04c353bbd 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 @@ import java.util.function.Supplier; * 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. @@ -925,6 +925,15 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { appInfo.splitSourceDirs, rollbackDataPolicy); } + @ExtThread + @Override + public void snapshotAndRestoreUserData(String packageName, List 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,