diff options
author | 2019-07-09 15:56:32 +0000 | |
---|---|---|
committer | 2019-07-09 15:56:32 +0000 | |
commit | 03ab1711c40a8df0232f94912a7577cb0e075b55 (patch) | |
tree | a8b41d23b5505c0059d6a7fa4a2e3dae21a91341 | |
parent | 582e98ef762429c15cfe677409d489aa96aad496 (diff) | |
parent | 278af8f43c72a67dd9c471b159e5e184fb3e5f0d (diff) |
Merge "Make ApexManager an abstract class"
-rw-r--r-- | services/core/java/com/android/server/pm/ApexManager.java | 708 | ||||
-rw-r--r-- | services/core/java/com/android/server/pm/PackageManagerService.java | 2 |
2 files changed, 416 insertions, 294 deletions
diff --git a/services/core/java/com/android/server/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java index 03224d1939b9..7e1bc79399b9 100644 --- a/services/core/java/com/android/server/pm/ApexManager.java +++ b/services/core/java/com/android/server/pm/ApexManager.java @@ -11,7 +11,7 @@ * 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.s + * limitations under the License. */ package com.android.server.pm; @@ -31,10 +31,8 @@ import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageParser; -import android.content.pm.PackageParser.PackageParserException; import android.os.RemoteException; import android.os.ServiceManager; -import android.os.ServiceManager.ServiceNotFoundException; import android.sysprop.ApexProperties; import android.util.Slog; @@ -55,103 +53,33 @@ import java.util.stream.Collectors; * ApexManager class handles communications with the apex service to perform operation and queries, * as well as providing caching to avoid unnecessary calls to the service. */ -class ApexManager { - static final String TAG = "ApexManager"; - private final IApexService mApexService; - private final Context mContext; - private final Object mLock = new Object(); - /** - * A map from {@code APEX packageName} to the {@Link PackageInfo} generated from the {@code - * AndroidManifest.xml} - * - * <p>Note that key of this map is {@code packageName} field of the corresponding {@code - * AndroidManifest.xml}. - */ - @GuardedBy("mLock") - private List<PackageInfo> mAllPackagesCache; - - ApexManager(Context context) { - mContext = context; - if (!isApexSupported()) { - mApexService = null; - return; - } - try { - mApexService = IApexService.Stub.asInterface( - ServiceManager.getServiceOrThrow("apexservice")); - } catch (ServiceNotFoundException e) { - throw new IllegalStateException("Required service apexservice not available"); - } - } +abstract class ApexManager { + + private static final String TAG = "ApexManager"; static final int MATCH_ACTIVE_PACKAGE = 1 << 0; static final int MATCH_FACTORY_PACKAGE = 1 << 1; - @IntDef( - flag = true, - prefix = { "MATCH_"}, - value = {MATCH_ACTIVE_PACKAGE, MATCH_FACTORY_PACKAGE}) - @Retention(RetentionPolicy.SOURCE) - @interface PackageInfoFlags{} - - void systemReady() { - if (!isApexSupported()) return; - mContext.registerReceiver(new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - onBootCompleted(); - mContext.unregisterReceiver(this); - } - }, new IntentFilter(Intent.ACTION_BOOT_COMPLETED)); - } - private void populateAllPackagesCacheIfNeeded() { - synchronized (mLock) { - if (mAllPackagesCache != null) { - return; - } + /** + * Returns an instance of either {@link ApexManagerImpl} or {@link ApexManagerNoOp} depending + * on whenever this device supports APEX, i.e. {@link ApexProperties#updatable()} evaluates to + * {@code true}. + */ + static ApexManager create(Context systemContext) { + if (ApexProperties.updatable().orElse(false)) { try { - mAllPackagesCache = new ArrayList<>(); - HashSet<String> activePackagesSet = new HashSet<>(); - HashSet<String> factoryPackagesSet = new HashSet<>(); - final ApexInfo[] allPkgs = mApexService.getAllPackages(); - for (ApexInfo ai : allPkgs) { - // If the device is using flattened APEX, don't report any APEX - // packages since they won't be managed or updated by PackageManager. - if ((new File(ai.modulePath)).isDirectory()) { - break; - } - try { - final PackageInfo pkg = PackageParser.generatePackageInfoFromApex( - ai, PackageManager.GET_META_DATA - | PackageManager.GET_SIGNING_CERTIFICATES); - mAllPackagesCache.add(pkg); - if (ai.isActive) { - if (activePackagesSet.contains(pkg.packageName)) { - throw new IllegalStateException( - "Two active packages have the same name: " - + pkg.packageName); - } - activePackagesSet.add(pkg.packageName); - } - if (ai.isFactory) { - if (factoryPackagesSet.contains(pkg.packageName)) { - throw new IllegalStateException( - "Two factory packages have the same name: " - + pkg.packageName); - } - factoryPackagesSet.add(pkg.packageName); - } - } catch (PackageParserException pe) { - throw new IllegalStateException("Unable to parse: " + ai, pe); - } - } - } catch (RemoteException re) { - Slog.e(TAG, "Unable to retrieve packages from apexservice: " + re.toString()); - throw new RuntimeException(re); + return new ApexManagerImpl(systemContext, IApexService.Stub.asInterface( + ServiceManager.getServiceOrThrow("apexservice"))); + } catch (ServiceManager.ServiceNotFoundException e) { + throw new IllegalStateException("Required service apexservice not available"); } + } else { + return new ApexManagerNoOp(); } } + abstract void systemReady(); + /** * Retrieves information about an APEX package. * @@ -164,22 +92,8 @@ class ApexManager { * @return a PackageInfo object with the information about the package, or null if the package * is not found. */ - @Nullable PackageInfo getPackageInfo(String packageName, @PackageInfoFlags int flags) { - if (!isApexSupported()) return null; - populateAllPackagesCacheIfNeeded(); - boolean matchActive = (flags & MATCH_ACTIVE_PACKAGE) != 0; - boolean matchFactory = (flags & MATCH_FACTORY_PACKAGE) != 0; - for (PackageInfo packageInfo: mAllPackagesCache) { - if (!packageInfo.packageName.equals(packageName)) { - continue; - } - if ((!matchActive || isActive(packageInfo)) - && (!matchFactory || isFactory(packageInfo))) { - return packageInfo; - } - } - return null; - } + @Nullable + abstract PackageInfo getPackageInfo(String packageName, @PackageInfoFlags int flags); /** * Retrieves information about all active APEX packages. @@ -187,14 +101,7 @@ class ApexManager { * @return a List of PackageInfo object, each one containing information about a different * active package. */ - List<PackageInfo> getActivePackages() { - if (!isApexSupported()) return Collections.emptyList(); - populateAllPackagesCacheIfNeeded(); - return mAllPackagesCache - .stream() - .filter(item -> isActive(item)) - .collect(Collectors.toList()); - } + abstract List<PackageInfo> getActivePackages(); /** * Retrieves information about all active pre-installed APEX packages. @@ -202,14 +109,7 @@ class ApexManager { * @return a List of PackageInfo object, each one containing information about a different * active pre-installed package. */ - List<PackageInfo> getFactoryPackages() { - if (!isApexSupported()) return Collections.emptyList(); - populateAllPackagesCacheIfNeeded(); - return mAllPackagesCache - .stream() - .filter(item -> isFactory(item)) - .collect(Collectors.toList()); - } + abstract List<PackageInfo> getFactoryPackages(); /** * Retrieves information about all inactive APEX packages. @@ -217,14 +117,7 @@ class ApexManager { * @return a List of PackageInfo object, each one containing information about a different * inactive package. */ - List<PackageInfo> getInactivePackages() { - if (!isApexSupported()) return Collections.emptyList(); - populateAllPackagesCacheIfNeeded(); - return mAllPackagesCache - .stream() - .filter(item -> !isActive(item)) - .collect(Collectors.toList()); - } + abstract List<PackageInfo> getInactivePackages(); /** * Checks if {@code packageName} is an apex package. @@ -232,16 +125,7 @@ class ApexManager { * @param packageName package to check. * @return {@code true} if {@code packageName} is an apex package. */ - boolean isApexPackage(String packageName) { - if (!isApexSupported()) return false; - populateAllPackagesCacheIfNeeded(); - for (PackageInfo packageInfo : mAllPackagesCache) { - if (packageInfo.packageName.equals(packageName)) { - return true; - } - } - return false; - } + abstract boolean isApexPackage(String packageName); /** * Retrieves information about an apexd staged session i.e. the internal state used by apexd to @@ -250,19 +134,8 @@ class ApexManager { * @param sessionId the identifier of the session. * @return an ApexSessionInfo object, or null if the session is not known. */ - @Nullable ApexSessionInfo getStagedSessionInfo(int sessionId) { - if (!isApexSupported()) return null; - try { - ApexSessionInfo apexSessionInfo = mApexService.getStagedSessionInfo(sessionId); - if (apexSessionInfo.isUnknown) { - return null; - } - return apexSessionInfo; - } catch (RemoteException re) { - Slog.e(TAG, "Unable to contact apexservice", re); - throw new RuntimeException(re); - } - } + @Nullable + abstract ApexSessionInfo getStagedSessionInfo(int sessionId); /** * Submit a staged session to apex service. This causes the apex service to perform some initial @@ -280,16 +153,8 @@ class ApexManager { * the session. * @return whether the submission of the session was successful. */ - boolean submitStagedSession( - int sessionId, @NonNull int[] childSessionIds, @NonNull ApexInfoList apexInfoList) { - if (!isApexSupported()) return false; - try { - return mApexService.submitStagedSession(sessionId, childSessionIds, apexInfoList); - } catch (RemoteException re) { - Slog.e(TAG, "Unable to contact apexservice", re); - throw new RuntimeException(re); - } - } + abstract boolean submitStagedSession( + int sessionId, @NonNull int[] childSessionIds, @NonNull ApexInfoList apexInfoList); /** * Mark a staged session previously submitted using {@code submitStagedSession} as ready to be @@ -298,15 +163,7 @@ class ApexManager { * @param sessionId the identifier of the {@link PackageInstallerSession} being marked as ready. * @return true upon success, false if the session is unknown. */ - boolean markStagedSessionReady(int sessionId) { - if (!isApexSupported()) return false; - try { - return mApexService.markStagedSessionReady(sessionId); - } catch (RemoteException re) { - Slog.e(TAG, "Unable to contact apexservice", re); - throw new RuntimeException(re); - } - } + abstract boolean markStagedSessionReady(int sessionId); /** * Marks a staged session as successful. @@ -316,44 +173,21 @@ class ApexManager { * @param sessionId the identifier of the {@link PackageInstallerSession} being marked as * successful. */ - void markStagedSessionSuccessful(int sessionId) { - if (!isApexSupported()) return; - try { - mApexService.markStagedSessionSuccessful(sessionId); - } catch (RemoteException re) { - Slog.e(TAG, "Unable to contact apexservice", re); - throw new RuntimeException(re); - } catch (Exception e) { - // It is fine to just log an exception in this case. APEXd will be able to recover in - // case markStagedSessionSuccessful fails. - Slog.e(TAG, "Failed to mark session " + sessionId + " as successful", e); - } - } + abstract void markStagedSessionSuccessful(int sessionId); /** * Whether the current device supports the management of APEX packages. * * @return true if APEX packages can be managed on this device, false otherwise. */ - boolean isApexSupported() { - return ApexProperties.updatable().orElse(false); - } + abstract boolean isApexSupported(); /** * Abandons the (only) active session previously submitted. * * @return {@code true} upon success, {@code false} if any remote exception occurs */ - boolean abortActiveSession() { - if (!isApexSupported()) return false; - try { - mApexService.abortActiveSession(); - return true; - } catch (RemoteException re) { - Slog.e(TAG, "Unable to contact apexservice", re); - return false; - } - } + abstract boolean abortActiveSession(); /** * Uninstalls given {@code apexPackage}. @@ -363,120 +197,408 @@ class ApexManager { * @param apexPackagePath package to uninstall. * @return {@code true} upon successful uninstall, {@code false} otherwise. */ - boolean uninstallApex(String apexPackagePath) { - if (!isApexSupported()) return false; - try { - mApexService.unstagePackages(Collections.singletonList(apexPackagePath)); - return true; - } catch (Exception e) { - return false; - } - } + abstract boolean uninstallApex(String apexPackagePath); /** - * Whether an APEX package is active or not. + * Dumps various state information to the provided {@link PrintWriter} object. * - * @param packageInfo the package to check - * @return {@code true} if this package is active, {@code false} otherwise. + * @param pw the {@link PrintWriter} object to send information to. + * @param packageName a {@link String} containing a package name, or {@code null}. If set, only + * information about that specific package will be dumped. */ - private static boolean isActive(PackageInfo packageInfo) { - return (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED) != 0; - } + abstract void dump(PrintWriter pw, @Nullable String packageName); - /** - * Whether the APEX package is pre-installed or not. - * - * @param packageInfo the package to check - * @return {@code true} if this package is pre-installed, {@code false} otherwise. - */ - private static boolean isFactory(PackageInfo packageInfo) { - return (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0; - } + @IntDef( + flag = true, + prefix = { "MATCH_"}, + value = {MATCH_ACTIVE_PACKAGE, MATCH_FACTORY_PACKAGE}) + @Retention(RetentionPolicy.SOURCE) + @interface PackageInfoFlags{} /** - * Dump information about the packages contained in a particular cache - * @param packagesCache the cache to print information about. - * @param packageName a {@link String} containing a package name, or {@code null}. If set, only - * information about that specific package will be dumped. - * @param ipw the {@link IndentingPrintWriter} object to send information to. + * An implementation of {@link ApexManager} that should be used in case device supports updating + * APEX packages. */ - void dumpFromPackagesCache( - List<PackageInfo> packagesCache, - @Nullable String packageName, - IndentingPrintWriter ipw) { - ipw.println(); - ipw.increaseIndent(); - for (PackageInfo pi : packagesCache) { - if (packageName != null && !packageName.equals(pi.packageName)) { - continue; + private static class ApexManagerImpl extends ApexManager { + private final IApexService mApexService; + private final Context mContext; + private final Object mLock = new Object(); + /** + * A map from {@code APEX packageName} to the {@Link PackageInfo} generated from the {@code + * AndroidManifest.xml} + * + * <p>Note that key of this map is {@code packageName} field of the corresponding {@code + * AndroidManifest.xml}. + */ + @GuardedBy("mLock") + private List<PackageInfo> mAllPackagesCache; + + ApexManagerImpl(Context context, IApexService apexService) { + mContext = context; + mApexService = apexService; + } + + /** + * Whether an APEX package is active or not. + * + * @param packageInfo the package to check + * @return {@code true} if this package is active, {@code false} otherwise. + */ + private static boolean isActive(PackageInfo packageInfo) { + return (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED) != 0; + } + + /** + * Whether the APEX package is pre-installed or not. + * + * @param packageInfo the package to check + * @return {@code true} if this package is pre-installed, {@code false} otherwise. + */ + private static boolean isFactory(PackageInfo packageInfo) { + return (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0; + } + + @Override + void systemReady() { + mContext.registerReceiver(new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + populateAllPackagesCacheIfNeeded(); + mContext.unregisterReceiver(this); + } + }, new IntentFilter(Intent.ACTION_BOOT_COMPLETED)); + } + + private void populateAllPackagesCacheIfNeeded() { + synchronized (mLock) { + if (mAllPackagesCache != null) { + return; + } + try { + mAllPackagesCache = new ArrayList<>(); + HashSet<String> activePackagesSet = new HashSet<>(); + HashSet<String> factoryPackagesSet = new HashSet<>(); + final ApexInfo[] allPkgs = mApexService.getAllPackages(); + for (ApexInfo ai : allPkgs) { + // If the device is using flattened APEX, don't report any APEX + // packages since they won't be managed or updated by PackageManager. + if ((new File(ai.modulePath)).isDirectory()) { + break; + } + try { + final PackageInfo pkg = PackageParser.generatePackageInfoFromApex( + ai, PackageManager.GET_META_DATA + | PackageManager.GET_SIGNING_CERTIFICATES); + mAllPackagesCache.add(pkg); + if (ai.isActive) { + if (activePackagesSet.contains(pkg.packageName)) { + throw new IllegalStateException( + "Two active packages have the same name: " + + pkg.packageName); + } + activePackagesSet.add(pkg.packageName); + } + if (ai.isFactory) { + if (factoryPackagesSet.contains(pkg.packageName)) { + throw new IllegalStateException( + "Two factory packages have the same name: " + + pkg.packageName); + } + factoryPackagesSet.add(pkg.packageName); + } + } catch (PackageParser.PackageParserException pe) { + throw new IllegalStateException("Unable to parse: " + ai, pe); + } + } + } catch (RemoteException re) { + Slog.e(TAG, "Unable to retrieve packages from apexservice: " + re.toString()); + throw new RuntimeException(re); + } } - ipw.println(pi.packageName); - ipw.increaseIndent(); - ipw.println("Version: " + pi.versionCode); - ipw.println("Path: " + pi.applicationInfo.sourceDir); - ipw.println("IsActive: " + isActive(pi)); - ipw.println("IsFactory: " + isFactory(pi)); - ipw.decreaseIndent(); } - ipw.decreaseIndent(); - ipw.println(); - } - /** - * Dumps various state information to the provided {@link PrintWriter} object. - * - * @param pw the {@link PrintWriter} object to send information to. - * @param packageName a {@link String} containing a package name, or {@code null}. If set, only - * information about that specific package will be dumped. - */ - void dump(PrintWriter pw, @Nullable String packageName) { - if (!isApexSupported()) return; - final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ", 120); - try { + @Override + @Nullable PackageInfo getPackageInfo(String packageName, @PackageInfoFlags int flags) { + populateAllPackagesCacheIfNeeded(); + boolean matchActive = (flags & MATCH_ACTIVE_PACKAGE) != 0; + boolean matchFactory = (flags & MATCH_FACTORY_PACKAGE) != 0; + for (PackageInfo packageInfo: mAllPackagesCache) { + if (!packageInfo.packageName.equals(packageName)) { + continue; + } + if ((!matchActive || isActive(packageInfo)) + && (!matchFactory || isFactory(packageInfo))) { + return packageInfo; + } + } + return null; + } + + @Override + List<PackageInfo> getActivePackages() { + populateAllPackagesCacheIfNeeded(); + return mAllPackagesCache + .stream() + .filter(item -> isActive(item)) + .collect(Collectors.toList()); + } + + @Override + List<PackageInfo> getFactoryPackages() { + populateAllPackagesCacheIfNeeded(); + return mAllPackagesCache + .stream() + .filter(item -> isFactory(item)) + .collect(Collectors.toList()); + } + + @Override + List<PackageInfo> getInactivePackages() { + populateAllPackagesCacheIfNeeded(); + return mAllPackagesCache + .stream() + .filter(item -> !isActive(item)) + .collect(Collectors.toList()); + } + + @Override + boolean isApexPackage(String packageName) { + if (!isApexSupported()) return false; populateAllPackagesCacheIfNeeded(); + for (PackageInfo packageInfo : mAllPackagesCache) { + if (packageInfo.packageName.equals(packageName)) { + return true; + } + } + return false; + } + + @Override + @Nullable ApexSessionInfo getStagedSessionInfo(int sessionId) { + try { + ApexSessionInfo apexSessionInfo = mApexService.getStagedSessionInfo(sessionId); + if (apexSessionInfo.isUnknown) { + return null; + } + return apexSessionInfo; + } catch (RemoteException re) { + Slog.e(TAG, "Unable to contact apexservice", re); + throw new RuntimeException(re); + } + } + + @Override + boolean submitStagedSession( + int sessionId, @NonNull int[] childSessionIds, @NonNull ApexInfoList apexInfoList) { + try { + return mApexService.submitStagedSession(sessionId, childSessionIds, apexInfoList); + } catch (RemoteException re) { + Slog.e(TAG, "Unable to contact apexservice", re); + throw new RuntimeException(re); + } + } + + @Override + boolean markStagedSessionReady(int sessionId) { + try { + return mApexService.markStagedSessionReady(sessionId); + } catch (RemoteException re) { + Slog.e(TAG, "Unable to contact apexservice", re); + throw new RuntimeException(re); + } + } + + @Override + void markStagedSessionSuccessful(int sessionId) { + try { + mApexService.markStagedSessionSuccessful(sessionId); + } catch (RemoteException re) { + Slog.e(TAG, "Unable to contact apexservice", re); + throw new RuntimeException(re); + } catch (Exception e) { + // It is fine to just log an exception in this case. APEXd will be able to recover + // in case markStagedSessionSuccessful fails. + Slog.e(TAG, "Failed to mark session " + sessionId + " as successful", e); + } + } + + @Override + boolean isApexSupported() { + return true; + } + + @Override + boolean abortActiveSession() { + try { + mApexService.abortActiveSession(); + return true; + } catch (RemoteException re) { + Slog.e(TAG, "Unable to contact apexservice", re); + return false; + } + } + + @Override + boolean uninstallApex(String apexPackagePath) { + try { + mApexService.unstagePackages(Collections.singletonList(apexPackagePath)); + return true; + } catch (Exception e) { + return false; + } + } + + /** + * Dump information about the packages contained in a particular cache + * @param packagesCache the cache to print information about. + * @param packageName a {@link String} containing a package name, or {@code null}. If set, + * only information about that specific package will be dumped. + * @param ipw the {@link IndentingPrintWriter} object to send information to. + */ + void dumpFromPackagesCache( + List<PackageInfo> packagesCache, + @Nullable String packageName, + IndentingPrintWriter ipw) { ipw.println(); - ipw.println("Active APEX packages:"); - dumpFromPackagesCache(getActivePackages(), packageName, ipw); - ipw.println("Inactive APEX packages:"); - dumpFromPackagesCache(getInactivePackages(), packageName, ipw); - ipw.println("Factory APEX packages:"); - dumpFromPackagesCache(getFactoryPackages(), packageName, ipw); - ipw.increaseIndent(); - ipw.println("APEX session state:"); ipw.increaseIndent(); - final ApexSessionInfo[] sessions = mApexService.getSessions(); - for (ApexSessionInfo si : sessions) { - ipw.println("Session ID: " + si.sessionId); - ipw.increaseIndent(); - if (si.isUnknown) { - ipw.println("State: UNKNOWN"); - } else if (si.isVerified) { - ipw.println("State: VERIFIED"); - } else if (si.isStaged) { - ipw.println("State: STAGED"); - } else if (si.isActivated) { - ipw.println("State: ACTIVATED"); - } else if (si.isActivationFailed) { - ipw.println("State: ACTIVATION FAILED"); - } else if (si.isSuccess) { - ipw.println("State: SUCCESS"); - } else if (si.isRollbackInProgress) { - ipw.println("State: ROLLBACK IN PROGRESS"); - } else if (si.isRolledBack) { - ipw.println("State: ROLLED BACK"); - } else if (si.isRollbackFailed) { - ipw.println("State: ROLLBACK FAILED"); + for (PackageInfo pi : packagesCache) { + if (packageName != null && !packageName.equals(pi.packageName)) { + continue; } + ipw.println(pi.packageName); + ipw.increaseIndent(); + ipw.println("Version: " + pi.versionCode); + ipw.println("Path: " + pi.applicationInfo.sourceDir); + ipw.println("IsActive: " + isActive(pi)); + ipw.println("IsFactory: " + isFactory(pi)); ipw.decreaseIndent(); } ipw.decreaseIndent(); - } catch (RemoteException e) { - ipw.println("Couldn't communicate with apexd."); + ipw.println(); + } + + @Override + void dump(PrintWriter pw, @Nullable String packageName) { + final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ", 120); + try { + populateAllPackagesCacheIfNeeded(); + ipw.println(); + ipw.println("Active APEX packages:"); + dumpFromPackagesCache(getActivePackages(), packageName, ipw); + ipw.println("Inactive APEX packages:"); + dumpFromPackagesCache(getInactivePackages(), packageName, ipw); + ipw.println("Factory APEX packages:"); + dumpFromPackagesCache(getFactoryPackages(), packageName, ipw); + ipw.increaseIndent(); + ipw.println("APEX session state:"); + ipw.increaseIndent(); + final ApexSessionInfo[] sessions = mApexService.getSessions(); + for (ApexSessionInfo si : sessions) { + ipw.println("Session ID: " + si.sessionId); + ipw.increaseIndent(); + if (si.isUnknown) { + ipw.println("State: UNKNOWN"); + } else if (si.isVerified) { + ipw.println("State: VERIFIED"); + } else if (si.isStaged) { + ipw.println("State: STAGED"); + } else if (si.isActivated) { + ipw.println("State: ACTIVATED"); + } else if (si.isActivationFailed) { + ipw.println("State: ACTIVATION FAILED"); + } else if (si.isSuccess) { + ipw.println("State: SUCCESS"); + } else if (si.isRollbackInProgress) { + ipw.println("State: ROLLBACK IN PROGRESS"); + } else if (si.isRolledBack) { + ipw.println("State: ROLLED BACK"); + } else if (si.isRollbackFailed) { + ipw.println("State: ROLLBACK FAILED"); + } + ipw.decreaseIndent(); + } + ipw.decreaseIndent(); + } catch (RemoteException e) { + ipw.println("Couldn't communicate with apexd."); + } } } - public void onBootCompleted() { - if (!isApexSupported()) return; - populateAllPackagesCacheIfNeeded(); + /** + * An implementation of {@link ApexManager} that should be used in case device does not support + * updating APEX packages. + */ + private static final class ApexManagerNoOp extends ApexManager { + + @Override + void systemReady() { + // No-op + } + + @Override + PackageInfo getPackageInfo(String packageName, int flags) { + return null; + } + + @Override + List<PackageInfo> getActivePackages() { + return Collections.emptyList(); + } + + @Override + List<PackageInfo> getFactoryPackages() { + return Collections.emptyList(); + } + + @Override + List<PackageInfo> getInactivePackages() { + return Collections.emptyList(); + } + + @Override + boolean isApexPackage(String packageName) { + return false; + } + + @Override + ApexSessionInfo getStagedSessionInfo(int sessionId) { + throw new UnsupportedOperationException(); + } + + @Override + boolean submitStagedSession(int sessionId, int[] childSessionIds, + ApexInfoList apexInfoList) { + throw new UnsupportedOperationException(); + } + + @Override + boolean markStagedSessionReady(int sessionId) { + throw new UnsupportedOperationException(); + } + + @Override + void markStagedSessionSuccessful(int sessionId) { + throw new UnsupportedOperationException(); + } + + @Override + boolean isApexSupported() { + return false; + } + + @Override + boolean abortActiveSession() { + throw new UnsupportedOperationException(); + } + + @Override + boolean uninstallApex(String apexPackagePath) { + throw new UnsupportedOperationException(); + } + + @Override + void dump(PrintWriter pw, String packageName) { + // No-op + } } } diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 232bca82aa9c..b14f481a2edb 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -2489,7 +2489,7 @@ public class PackageManagerService extends IPackageManager.Stub mProtectedPackages = new ProtectedPackages(mContext); - mApexManager = new ApexManager(context); + mApexManager = ApexManager.create(context); // CHECKSTYLE:OFF IndentationCheck synchronized (mInstallLock) { // writer |