Loading services/core/java/com/android/server/pm/InstallDependencyHelper.java +69 −51 Original line number Original line Diff line number Diff line Loading @@ -32,11 +32,13 @@ import android.content.pm.dependencyinstaller.DependencyInstallerCallback; import android.content.pm.dependencyinstaller.IDependencyInstallerCallback; import android.content.pm.dependencyinstaller.IDependencyInstallerCallback; import android.content.pm.dependencyinstaller.IDependencyInstallerService; import android.content.pm.dependencyinstaller.IDependencyInstallerService; import android.content.pm.parsing.PackageLite; import android.content.pm.parsing.PackageLite; import android.os.Binder; import android.os.Handler; import android.os.Handler; import android.os.OutcomeReceiver; import android.os.OutcomeReceiver; import android.os.Process; import android.os.Process; import android.os.RemoteException; import android.os.RemoteException; import android.os.UserHandle; import android.os.UserHandle; import android.util.ArrayMap; import android.util.ArraySet; import android.util.ArraySet; import android.util.Slog; import android.util.Slog; Loading @@ -63,12 +65,11 @@ public class InstallDependencyHelper { private final Context mContext; private final Context mContext; private final SharedLibrariesImpl mSharedLibraries; private final SharedLibrariesImpl mSharedLibraries; private final PackageInstallerService mPackageInstallerService; private final PackageInstallerService mPackageInstallerService; private final Object mRemoteServiceLock = new Object(); @GuardedBy("mTrackers") @GuardedBy("mTrackers") private final List<DependencyInstallTracker> mTrackers = new ArrayList<>(); private final List<DependencyInstallTracker> mTrackers = new ArrayList<>(); @GuardedBy("mRemoteServices") @GuardedBy("mRemoteServiceLock") private final ArrayMap<Integer, ServiceConnector<IDependencyInstallerService>> mRemoteServices = private ServiceConnector<IDependencyInstallerService> mRemoteService = null; new ArrayMap<>(); InstallDependencyHelper(Context context, SharedLibrariesImpl sharedLibraries, InstallDependencyHelper(Context context, SharedLibrariesImpl sharedLibraries, PackageInstallerService packageInstallerService) { PackageInstallerService packageInstallerService) { Loading Loading @@ -97,13 +98,18 @@ public class InstallDependencyHelper { if (missing.isEmpty()) { if (missing.isEmpty()) { if (DEBUG) { if (DEBUG) { Slog.d(TAG, "No missing dependency for " + pkg); Slog.d(TAG, "No missing dependency for " + pkg.getPackageName()); } } // No need for dependency resolution. Move to installation directly. // No need for dependency resolution. Move to installation directly. callback.onResult(null); callback.onResult(null); return; return; } } if (DEBUG) { Slog.d(TAG, "Missing dependencies found for pkg: " + pkg.getPackageName() + " user: " + userId); } if (!bindToDependencyInstallerIfNeeded(userId, handler, snapshot)) { if (!bindToDependencyInstallerIfNeeded(userId, handler, snapshot)) { onError(callback, "Dependency Installer Service not found"); onError(callback, "Dependency Installer Service not found"); return; return; Loading @@ -112,8 +118,8 @@ public class InstallDependencyHelper { IDependencyInstallerCallback serviceCallback = IDependencyInstallerCallback serviceCallback = new DependencyInstallerCallbackCallOnce(handler, callback, userId); new DependencyInstallerCallbackCallOnce(handler, callback, userId); boolean scheduleSuccess; boolean scheduleSuccess; synchronized (mRemoteServiceLock) { synchronized (mRemoteServices) { scheduleSuccess = mRemoteService.run(service -> { scheduleSuccess = mRemoteServices.get(userId).run(service -> { service.onDependenciesRequired(missing, service.onDependenciesRequired(missing, new DependencyInstallerCallback(serviceCallback.asBinder())); new DependencyInstallerCallback(serviceCallback.asBinder())); }); }); Loading Loading @@ -149,15 +155,17 @@ public class InstallDependencyHelper { private boolean bindToDependencyInstallerIfNeeded(int userId, Handler handler, private boolean bindToDependencyInstallerIfNeeded(int userId, Handler handler, Computer snapshot) { Computer snapshot) { synchronized (mRemoteServiceLock) { synchronized (mRemoteServices) { if (mRemoteService != null) { if (mRemoteServices.containsKey(userId)) { if (DEBUG) { if (DEBUG) { Slog.i(TAG, "DependencyInstallerService already bound"); Slog.i(TAG, "DependencyInstallerService for user " + userId + " already bound"); } } return true; return true; } } } } Slog.i(TAG, "Attempting to bind to Dependency Installer Service for user " + userId); RoleManager roleManager = mContext.getSystemService(RoleManager.class); RoleManager roleManager = mContext.getSystemService(RoleManager.class); if (roleManager == null) { if (roleManager == null) { Slog.w(TAG, "Cannot find RoleManager system service"); Slog.w(TAG, "Cannot find RoleManager system service"); Loading @@ -166,7 +174,7 @@ public class InstallDependencyHelper { List<String> holders = roleManager.getRoleHoldersAsUser( List<String> holders = roleManager.getRoleHoldersAsUser( ROLE_SYSTEM_DEPENDENCY_INSTALLER, UserHandle.of(userId)); ROLE_SYSTEM_DEPENDENCY_INSTALLER, UserHandle.of(userId)); if (holders.isEmpty()) { if (holders.isEmpty()) { Slog.w(TAG, "No holders of ROLE_SYSTEM_DEPENDENCY_INSTALLER found"); Slog.w(TAG, "No holders of ROLE_SYSTEM_DEPENDENCY_INSTALLER found for user " + userId); return false; return false; } } Loading @@ -178,6 +186,8 @@ public class InstallDependencyHelper { /*includeInstantApps*/ false, /*resolveForStart*/ false); /*includeInstantApps*/ false, /*resolveForStart*/ false); if (resolvedIntents.isEmpty()) { if (resolvedIntents.isEmpty()) { Slog.w(TAG, "No package holding ROLE_SYSTEM_DEPENDENCY_INSTALLER found for user " + userId); return false; return false; } } Loading Loading @@ -206,13 +216,14 @@ public class InstallDependencyHelper { }; }; synchronized (mRemoteServiceLock) { synchronized (mRemoteServices) { // Some other thread managed to connect to the service first // Some other thread managed to connect to the service first if (mRemoteService != null) { if (mRemoteServices.containsKey(userId)) { return true; return true; } } mRemoteService = serviceConnector; mRemoteServices.put(userId, serviceConnector); mRemoteService.setServiceLifecycleCallbacks( // Block the lock until we connect to the service serviceConnector.setServiceLifecycleCallbacks( new ServiceConnector.ServiceLifecycleCallbacks<>() { new ServiceConnector.ServiceLifecycleCallbacks<>() { @Override @Override public void onDisconnected(@NonNull IDependencyInstallerService service) { public void onDisconnected(@NonNull IDependencyInstallerService service) { Loading @@ -228,17 +239,18 @@ public class InstallDependencyHelper { } } private void destroy() { private void destroy() { synchronized (mRemoteServiceLock) { synchronized (mRemoteServices) { if (mRemoteService != null) { if (mRemoteServices.containsKey(userId)) { mRemoteService.unbind(); mRemoteServices.get(userId).unbind(); mRemoteService = null; mRemoteServices.remove(userId); } } } } } } }); }); AndroidFuture<IDependencyInstallerService> unusedFuture = mRemoteService.connect(); AndroidFuture<IDependencyInstallerService> unusedFuture = serviceConnector.connect(); } } Slog.i(TAG, "Successfully bound to Dependency Installer Service for user " + userId); return true; return true; } } Loading Loading @@ -318,6 +330,7 @@ public class InstallDependencyHelper { Slog.d(TAG, "onAllDependenciesResolved started"); Slog.d(TAG, "onAllDependenciesResolved started"); } } try { // Before creating any tracker, validate the arguments // Before creating any tracker, validate the arguments ArraySet<Integer> validSessionIds = validateSessionIds(sessionIds); ArraySet<Integer> validSessionIds = validateSessionIds(sessionIds); Loading @@ -340,9 +353,18 @@ public class InstallDependencyHelper { // Don't wait for sessions that finished already // Don't wait for sessions that finished already if (sessionInfo == null) { if (sessionInfo == null) { Binder.withCleanCallingIdentity(() -> { notifySessionComplete(sessionId, /*success=*/ true); notifySessionComplete(sessionId, /*success=*/ true); }); } } } } } catch (Exception e) { // Allow calling the callback again synchronized (this) { mDependencyInstallerCallbackInvoked = false; } throw e; } } } @Override @Override Loading @@ -354,7 +376,10 @@ public class InstallDependencyHelper { } } mDependencyInstallerCallbackInvoked = true; mDependencyInstallerCallbackInvoked = true; } } Binder.withCleanCallingIdentity(() -> { onError(mCallback, "Failed to resolve all dependencies automatically"); onError(mCallback, "Failed to resolve all dependencies automatically"); }); } } private ArraySet<Integer> validateSessionIds(int[] sessionIds) { private ArraySet<Integer> validateSessionIds(int[] sessionIds) { Loading @@ -369,7 +394,8 @@ public class InstallDependencyHelper { // Continue waiting if session exists and hasn't passed or failed yet. // Continue waiting if session exists and hasn't passed or failed yet. if (sessionInfo != null) { if (sessionInfo != null) { if (sessionInfo.isSessionFailed) { if (sessionInfo.isSessionFailed) { throwValidationError("Session already finished: " + sessionId); throw new IllegalArgumentException("Session already finished: " + sessionId); } } // Wait for session to finish install if it's not already successful. // Wait for session to finish install if it's not already successful. Loading Loading @@ -398,25 +424,17 @@ public class InstallDependencyHelper { s -> s.sessionId == sessionId).findFirst().orElse(null); s -> s.sessionId == sessionId).findFirst().orElse(null); if (sessionInfo == null) { if (sessionInfo == null) { throwValidationError("Failed to find session: " + sessionId); throw new IllegalArgumentException("Failed to find session: " + sessionId); } } // Historical session must have been successful, otherwise throw IAE. // Historical session must have been successful, otherwise throw IAE. if (!sessionInfo.isSessionApplied) { if (!sessionInfo.isSessionApplied) { throwValidationError("Session already finished: " + sessionId); throw new IllegalArgumentException("Session already finished: " + sessionId); } } } } return validSessionIds; return validSessionIds; } } private void throwValidationError(String msg) { // Allow client to invoke callback again. synchronized (this) { mDependencyInstallerCallbackInvoked = false; } throw new IllegalArgumentException(msg); } } } /** /** Loading Loading
services/core/java/com/android/server/pm/InstallDependencyHelper.java +69 −51 Original line number Original line Diff line number Diff line Loading @@ -32,11 +32,13 @@ import android.content.pm.dependencyinstaller.DependencyInstallerCallback; import android.content.pm.dependencyinstaller.IDependencyInstallerCallback; import android.content.pm.dependencyinstaller.IDependencyInstallerCallback; import android.content.pm.dependencyinstaller.IDependencyInstallerService; import android.content.pm.dependencyinstaller.IDependencyInstallerService; import android.content.pm.parsing.PackageLite; import android.content.pm.parsing.PackageLite; import android.os.Binder; import android.os.Handler; import android.os.Handler; import android.os.OutcomeReceiver; import android.os.OutcomeReceiver; import android.os.Process; import android.os.Process; import android.os.RemoteException; import android.os.RemoteException; import android.os.UserHandle; import android.os.UserHandle; import android.util.ArrayMap; import android.util.ArraySet; import android.util.ArraySet; import android.util.Slog; import android.util.Slog; Loading @@ -63,12 +65,11 @@ public class InstallDependencyHelper { private final Context mContext; private final Context mContext; private final SharedLibrariesImpl mSharedLibraries; private final SharedLibrariesImpl mSharedLibraries; private final PackageInstallerService mPackageInstallerService; private final PackageInstallerService mPackageInstallerService; private final Object mRemoteServiceLock = new Object(); @GuardedBy("mTrackers") @GuardedBy("mTrackers") private final List<DependencyInstallTracker> mTrackers = new ArrayList<>(); private final List<DependencyInstallTracker> mTrackers = new ArrayList<>(); @GuardedBy("mRemoteServices") @GuardedBy("mRemoteServiceLock") private final ArrayMap<Integer, ServiceConnector<IDependencyInstallerService>> mRemoteServices = private ServiceConnector<IDependencyInstallerService> mRemoteService = null; new ArrayMap<>(); InstallDependencyHelper(Context context, SharedLibrariesImpl sharedLibraries, InstallDependencyHelper(Context context, SharedLibrariesImpl sharedLibraries, PackageInstallerService packageInstallerService) { PackageInstallerService packageInstallerService) { Loading Loading @@ -97,13 +98,18 @@ public class InstallDependencyHelper { if (missing.isEmpty()) { if (missing.isEmpty()) { if (DEBUG) { if (DEBUG) { Slog.d(TAG, "No missing dependency for " + pkg); Slog.d(TAG, "No missing dependency for " + pkg.getPackageName()); } } // No need for dependency resolution. Move to installation directly. // No need for dependency resolution. Move to installation directly. callback.onResult(null); callback.onResult(null); return; return; } } if (DEBUG) { Slog.d(TAG, "Missing dependencies found for pkg: " + pkg.getPackageName() + " user: " + userId); } if (!bindToDependencyInstallerIfNeeded(userId, handler, snapshot)) { if (!bindToDependencyInstallerIfNeeded(userId, handler, snapshot)) { onError(callback, "Dependency Installer Service not found"); onError(callback, "Dependency Installer Service not found"); return; return; Loading @@ -112,8 +118,8 @@ public class InstallDependencyHelper { IDependencyInstallerCallback serviceCallback = IDependencyInstallerCallback serviceCallback = new DependencyInstallerCallbackCallOnce(handler, callback, userId); new DependencyInstallerCallbackCallOnce(handler, callback, userId); boolean scheduleSuccess; boolean scheduleSuccess; synchronized (mRemoteServiceLock) { synchronized (mRemoteServices) { scheduleSuccess = mRemoteService.run(service -> { scheduleSuccess = mRemoteServices.get(userId).run(service -> { service.onDependenciesRequired(missing, service.onDependenciesRequired(missing, new DependencyInstallerCallback(serviceCallback.asBinder())); new DependencyInstallerCallback(serviceCallback.asBinder())); }); }); Loading Loading @@ -149,15 +155,17 @@ public class InstallDependencyHelper { private boolean bindToDependencyInstallerIfNeeded(int userId, Handler handler, private boolean bindToDependencyInstallerIfNeeded(int userId, Handler handler, Computer snapshot) { Computer snapshot) { synchronized (mRemoteServiceLock) { synchronized (mRemoteServices) { if (mRemoteService != null) { if (mRemoteServices.containsKey(userId)) { if (DEBUG) { if (DEBUG) { Slog.i(TAG, "DependencyInstallerService already bound"); Slog.i(TAG, "DependencyInstallerService for user " + userId + " already bound"); } } return true; return true; } } } } Slog.i(TAG, "Attempting to bind to Dependency Installer Service for user " + userId); RoleManager roleManager = mContext.getSystemService(RoleManager.class); RoleManager roleManager = mContext.getSystemService(RoleManager.class); if (roleManager == null) { if (roleManager == null) { Slog.w(TAG, "Cannot find RoleManager system service"); Slog.w(TAG, "Cannot find RoleManager system service"); Loading @@ -166,7 +174,7 @@ public class InstallDependencyHelper { List<String> holders = roleManager.getRoleHoldersAsUser( List<String> holders = roleManager.getRoleHoldersAsUser( ROLE_SYSTEM_DEPENDENCY_INSTALLER, UserHandle.of(userId)); ROLE_SYSTEM_DEPENDENCY_INSTALLER, UserHandle.of(userId)); if (holders.isEmpty()) { if (holders.isEmpty()) { Slog.w(TAG, "No holders of ROLE_SYSTEM_DEPENDENCY_INSTALLER found"); Slog.w(TAG, "No holders of ROLE_SYSTEM_DEPENDENCY_INSTALLER found for user " + userId); return false; return false; } } Loading @@ -178,6 +186,8 @@ public class InstallDependencyHelper { /*includeInstantApps*/ false, /*resolveForStart*/ false); /*includeInstantApps*/ false, /*resolveForStart*/ false); if (resolvedIntents.isEmpty()) { if (resolvedIntents.isEmpty()) { Slog.w(TAG, "No package holding ROLE_SYSTEM_DEPENDENCY_INSTALLER found for user " + userId); return false; return false; } } Loading Loading @@ -206,13 +216,14 @@ public class InstallDependencyHelper { }; }; synchronized (mRemoteServiceLock) { synchronized (mRemoteServices) { // Some other thread managed to connect to the service first // Some other thread managed to connect to the service first if (mRemoteService != null) { if (mRemoteServices.containsKey(userId)) { return true; return true; } } mRemoteService = serviceConnector; mRemoteServices.put(userId, serviceConnector); mRemoteService.setServiceLifecycleCallbacks( // Block the lock until we connect to the service serviceConnector.setServiceLifecycleCallbacks( new ServiceConnector.ServiceLifecycleCallbacks<>() { new ServiceConnector.ServiceLifecycleCallbacks<>() { @Override @Override public void onDisconnected(@NonNull IDependencyInstallerService service) { public void onDisconnected(@NonNull IDependencyInstallerService service) { Loading @@ -228,17 +239,18 @@ public class InstallDependencyHelper { } } private void destroy() { private void destroy() { synchronized (mRemoteServiceLock) { synchronized (mRemoteServices) { if (mRemoteService != null) { if (mRemoteServices.containsKey(userId)) { mRemoteService.unbind(); mRemoteServices.get(userId).unbind(); mRemoteService = null; mRemoteServices.remove(userId); } } } } } } }); }); AndroidFuture<IDependencyInstallerService> unusedFuture = mRemoteService.connect(); AndroidFuture<IDependencyInstallerService> unusedFuture = serviceConnector.connect(); } } Slog.i(TAG, "Successfully bound to Dependency Installer Service for user " + userId); return true; return true; } } Loading Loading @@ -318,6 +330,7 @@ public class InstallDependencyHelper { Slog.d(TAG, "onAllDependenciesResolved started"); Slog.d(TAG, "onAllDependenciesResolved started"); } } try { // Before creating any tracker, validate the arguments // Before creating any tracker, validate the arguments ArraySet<Integer> validSessionIds = validateSessionIds(sessionIds); ArraySet<Integer> validSessionIds = validateSessionIds(sessionIds); Loading @@ -340,9 +353,18 @@ public class InstallDependencyHelper { // Don't wait for sessions that finished already // Don't wait for sessions that finished already if (sessionInfo == null) { if (sessionInfo == null) { Binder.withCleanCallingIdentity(() -> { notifySessionComplete(sessionId, /*success=*/ true); notifySessionComplete(sessionId, /*success=*/ true); }); } } } } } catch (Exception e) { // Allow calling the callback again synchronized (this) { mDependencyInstallerCallbackInvoked = false; } throw e; } } } @Override @Override Loading @@ -354,7 +376,10 @@ public class InstallDependencyHelper { } } mDependencyInstallerCallbackInvoked = true; mDependencyInstallerCallbackInvoked = true; } } Binder.withCleanCallingIdentity(() -> { onError(mCallback, "Failed to resolve all dependencies automatically"); onError(mCallback, "Failed to resolve all dependencies automatically"); }); } } private ArraySet<Integer> validateSessionIds(int[] sessionIds) { private ArraySet<Integer> validateSessionIds(int[] sessionIds) { Loading @@ -369,7 +394,8 @@ public class InstallDependencyHelper { // Continue waiting if session exists and hasn't passed or failed yet. // Continue waiting if session exists and hasn't passed or failed yet. if (sessionInfo != null) { if (sessionInfo != null) { if (sessionInfo.isSessionFailed) { if (sessionInfo.isSessionFailed) { throwValidationError("Session already finished: " + sessionId); throw new IllegalArgumentException("Session already finished: " + sessionId); } } // Wait for session to finish install if it's not already successful. // Wait for session to finish install if it's not already successful. Loading Loading @@ -398,25 +424,17 @@ public class InstallDependencyHelper { s -> s.sessionId == sessionId).findFirst().orElse(null); s -> s.sessionId == sessionId).findFirst().orElse(null); if (sessionInfo == null) { if (sessionInfo == null) { throwValidationError("Failed to find session: " + sessionId); throw new IllegalArgumentException("Failed to find session: " + sessionId); } } // Historical session must have been successful, otherwise throw IAE. // Historical session must have been successful, otherwise throw IAE. if (!sessionInfo.isSessionApplied) { if (!sessionInfo.isSessionApplied) { throwValidationError("Session already finished: " + sessionId); throw new IllegalArgumentException("Session already finished: " + sessionId); } } } } return validSessionIds; return validSessionIds; } } private void throwValidationError(String msg) { // Allow client to invoke callback again. synchronized (this) { mDependencyInstallerCallbackInvoked = false; } throw new IllegalArgumentException(msg); } } } /** /** Loading