Loading services/core/java/com/android/server/pm/ApexManager.java +415 −293 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading @@ -55,8 +53,173 @@ 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"; 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; /** * 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 { 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. * * @param packageName the package name to look for. Note that this is the package name reported * in the APK container manifest (i.e. AndroidManifest.xml), which might * differ from the one reported in the APEX manifest (i.e. * apex_manifest.json). * @param flags the type of package to return. This may match to active packages * and factory (pre-installed) packages. * @return a PackageInfo object with the information about the package, or null if the package * is not found. */ @Nullable abstract PackageInfo getPackageInfo(String packageName, @PackageInfoFlags int flags); /** * Retrieves information about all active APEX packages. * * @return a List of PackageInfo object, each one containing information about a different * active package. */ abstract List<PackageInfo> getActivePackages(); /** * Retrieves information about all active pre-installed APEX packages. * * @return a List of PackageInfo object, each one containing information about a different * active pre-installed package. */ abstract List<PackageInfo> getFactoryPackages(); /** * Retrieves information about all inactive APEX packages. * * @return a List of PackageInfo object, each one containing information about a different * inactive package. */ abstract List<PackageInfo> getInactivePackages(); /** * Checks if {@code packageName} is an apex package. * * @param packageName package to check. * @return {@code true} if {@code packageName} is an apex package. */ abstract boolean isApexPackage(String packageName); /** * Retrieves information about an apexd staged session i.e. the internal state used by apexd to * track the different states of a session. * * @param sessionId the identifier of the session. * @return an ApexSessionInfo object, or null if the session is not known. */ @Nullable abstract ApexSessionInfo getStagedSessionInfo(int sessionId); /** * Submit a staged session to apex service. This causes the apex service to perform some initial * verification and accept or reject the session. Submitting a session successfully is not * enough for it to be activated at the next boot, the caller needs to call * {@link #markStagedSessionReady(int)}. * * @param sessionId the identifier of the {@link PackageInstallerSession} being submitted. * @param childSessionIds if {@code sessionId} is a multi-package session, this should contain * an array of identifiers of all the child sessions. Otherwise it should * be an empty array. * @param apexInfoList this is an output parameter, which needs to be initialized by tha caller * and will be filled with a list of {@link ApexInfo} objects, each of which * contains metadata about one of the packages being submitted as part of * the session. * @return whether the submission of the session was successful. */ abstract boolean submitStagedSession( int sessionId, @NonNull int[] childSessionIds, @NonNull ApexInfoList apexInfoList); /** * Mark a staged session previously submitted using {@code submitStagedSession} as ready to be * applied at next reboot. * * @param sessionId the identifier of the {@link PackageInstallerSession} being marked as ready. * @return true upon success, false if the session is unknown. */ abstract boolean markStagedSessionReady(int sessionId); /** * Marks a staged session as successful. * * <p>Only activated session can be marked as successful. * * @param sessionId the identifier of the {@link PackageInstallerSession} being marked as * successful. */ 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. */ abstract boolean isApexSupported(); /** * Abandons the (only) active session previously submitted. * * @return {@code true} upon success, {@code false} if any remote exception occurs */ abstract boolean abortActiveSession(); /** * Uninstalls given {@code apexPackage}. * * <p>NOTE. Device must be rebooted in order for uninstall to take effect. * * @param apexPackagePath package to uninstall. * @return {@code true} upon successful uninstall, {@code false} otherwise. */ abstract boolean uninstallApex(String apexPackagePath); /** * 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. */ abstract void dump(PrintWriter pw, @Nullable String packageName); @IntDef( flag = true, prefix = { "MATCH_"}, value = {MATCH_ACTIVE_PACKAGE, MATCH_FACTORY_PACKAGE}) @Retention(RetentionPolicy.SOURCE) @interface PackageInfoFlags{} /** * An implementation of {@link ApexManager} that should be used in case device supports updating * APEX packages. */ private static class ApexManagerImpl extends ApexManager { private final IApexService mApexService; private final Context mContext; private final Object mLock = new Object(); Loading @@ -70,35 +233,37 @@ class ApexManager { @GuardedBy("mLock") private List<PackageInfo> mAllPackagesCache; ApexManager(Context context) { ApexManagerImpl(Context context, IApexService apexService) { 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"); 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; } 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{} /** * 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() { if (!isApexSupported()) return; mContext.registerReceiver(new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { onBootCompleted(); populateAllPackagesCacheIfNeeded(); mContext.unregisterReceiver(this); } }, new IntentFilter(Intent.ACTION_BOOT_COMPLETED)); Loading Loading @@ -141,7 +306,7 @@ class ApexManager { } factoryPackagesSet.add(pkg.packageName); } } catch (PackageParserException pe) { } catch (PackageParser.PackageParserException pe) { throw new IllegalStateException("Unable to parse: " + ai, pe); } } Loading @@ -152,20 +317,8 @@ class ApexManager { } } /** * Retrieves information about an APEX package. * * @param packageName the package name to look for. Note that this is the package name reported * in the APK container manifest (i.e. AndroidManifest.xml), which might * differ from the one reported in the APEX manifest (i.e. * apex_manifest.json). * @param flags the type of package to return. This may match to active packages * and factory (pre-installed) packages. * @return a PackageInfo object with the information about the package, or null if the package * is not found. */ @Override @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; Loading @@ -181,14 +334,8 @@ class ApexManager { return null; } /** * Retrieves information about all active APEX packages. * * @return a List of PackageInfo object, each one containing information about a different * active package. */ @Override List<PackageInfo> getActivePackages() { if (!isApexSupported()) return Collections.emptyList(); populateAllPackagesCacheIfNeeded(); return mAllPackagesCache .stream() Loading @@ -196,14 +343,8 @@ class ApexManager { .collect(Collectors.toList()); } /** * Retrieves information about all active pre-installed APEX packages. * * @return a List of PackageInfo object, each one containing information about a different * active pre-installed package. */ @Override List<PackageInfo> getFactoryPackages() { if (!isApexSupported()) return Collections.emptyList(); populateAllPackagesCacheIfNeeded(); return mAllPackagesCache .stream() Loading @@ -211,14 +352,8 @@ class ApexManager { .collect(Collectors.toList()); } /** * Retrieves information about all inactive APEX packages. * * @return a List of PackageInfo object, each one containing information about a different * inactive package. */ @Override List<PackageInfo> getInactivePackages() { if (!isApexSupported()) return Collections.emptyList(); populateAllPackagesCacheIfNeeded(); return mAllPackagesCache .stream() Loading @@ -226,12 +361,7 @@ class ApexManager { .collect(Collectors.toList()); } /** * Checks if {@code packageName} is an apex package. * * @param packageName package to check. * @return {@code true} if {@code packageName} is an apex package. */ @Override boolean isApexPackage(String packageName) { if (!isApexSupported()) return false; populateAllPackagesCacheIfNeeded(); Loading @@ -243,15 +373,8 @@ class ApexManager { return false; } /** * Retrieves information about an apexd staged session i.e. the internal state used by apexd to * track the different states of a session. * * @param sessionId the identifier of the session. * @return an ApexSessionInfo object, or null if the session is not known. */ @Override @Nullable ApexSessionInfo getStagedSessionInfo(int sessionId) { if (!isApexSupported()) return null; try { ApexSessionInfo apexSessionInfo = mApexService.getStagedSessionInfo(sessionId); if (apexSessionInfo.isUnknown) { Loading @@ -264,25 +387,9 @@ class ApexManager { } } /** * Submit a staged session to apex service. This causes the apex service to perform some initial * verification and accept or reject the session. Submitting a session successfully is not * enough for it to be activated at the next boot, the caller needs to call * {@link #markStagedSessionReady(int)}. * * @param sessionId the identifier of the {@link PackageInstallerSession} being submitted. * @param childSessionIds if {@code sessionId} is a multi-package session, this should contain * an array of identifiers of all the child sessions. Otherwise it should * be an empty array. * @param apexInfoList this is an output parameter, which needs to be initialized by tha caller * and will be filled with a list of {@link ApexInfo} objects, each of which * contains metadata about one of the packages being submitted as part of * the session. * @return whether the submission of the session was successful. */ @Override boolean submitStagedSession( int sessionId, @NonNull int[] childSessionIds, @NonNull ApexInfoList apexInfoList) { if (!isApexSupported()) return false; try { return mApexService.submitStagedSession(sessionId, childSessionIds, apexInfoList); } catch (RemoteException re) { Loading @@ -291,15 +398,8 @@ class ApexManager { } } /** * Mark a staged session previously submitted using {@code submitStagedSession} as ready to be * applied at next reboot. * * @param sessionId the identifier of the {@link PackageInstallerSession} being marked as ready. * @return true upon success, false if the session is unknown. */ @Override boolean markStagedSessionReady(int sessionId) { if (!isApexSupported()) return false; try { return mApexService.markStagedSessionReady(sessionId); } catch (RemoteException re) { Loading @@ -308,44 +408,27 @@ class ApexManager { } } /** * Marks a staged session as successful. * * <p>Only activated session can be marked as successful. * * @param sessionId the identifier of the {@link PackageInstallerSession} being marked as * successful. */ @Override 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. // 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); } } /** * Whether the current device supports the management of APEX packages. * * @return true if APEX packages can be managed on this device, false otherwise. */ @Override boolean isApexSupported() { return ApexProperties.updatable().orElse(false); return true; } /** * Abandons the (only) active session previously submitted. * * @return {@code true} upon success, {@code false} if any remote exception occurs */ @Override boolean abortActiveSession() { if (!isApexSupported()) return false; try { mApexService.abortActiveSession(); return true; Loading @@ -355,16 +438,8 @@ class ApexManager { } } /** * Uninstalls given {@code apexPackage}. * * <p>NOTE. Device must be rebooted in order for uninstall to take effect. * * @param apexPackagePath package to uninstall. * @return {@code true} upon successful uninstall, {@code false} otherwise. */ @Override boolean uninstallApex(String apexPackagePath) { if (!isApexSupported()) return false; try { mApexService.unstagePackages(Collections.singletonList(apexPackagePath)); return true; Loading @@ -373,31 +448,11 @@ class ApexManager { } } /** * 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; } /** * 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 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( Loading @@ -422,15 +477,8 @@ class ApexManager { 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. */ @Override void dump(PrintWriter pw, @Nullable String packageName) { if (!isApexSupported()) return; final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ", 120); try { populateAllPackagesCacheIfNeeded(); Loading Loading @@ -474,9 +522,83 @@ class ApexManager { 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 } } } services/core/java/com/android/server/pm/PackageManagerService.java +1 −1 Original line number Diff line number Diff line Loading @@ -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 Loading
services/core/java/com/android/server/pm/ApexManager.java +415 −293 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading @@ -55,8 +53,173 @@ 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"; 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; /** * 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 { 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. * * @param packageName the package name to look for. Note that this is the package name reported * in the APK container manifest (i.e. AndroidManifest.xml), which might * differ from the one reported in the APEX manifest (i.e. * apex_manifest.json). * @param flags the type of package to return. This may match to active packages * and factory (pre-installed) packages. * @return a PackageInfo object with the information about the package, or null if the package * is not found. */ @Nullable abstract PackageInfo getPackageInfo(String packageName, @PackageInfoFlags int flags); /** * Retrieves information about all active APEX packages. * * @return a List of PackageInfo object, each one containing information about a different * active package. */ abstract List<PackageInfo> getActivePackages(); /** * Retrieves information about all active pre-installed APEX packages. * * @return a List of PackageInfo object, each one containing information about a different * active pre-installed package. */ abstract List<PackageInfo> getFactoryPackages(); /** * Retrieves information about all inactive APEX packages. * * @return a List of PackageInfo object, each one containing information about a different * inactive package. */ abstract List<PackageInfo> getInactivePackages(); /** * Checks if {@code packageName} is an apex package. * * @param packageName package to check. * @return {@code true} if {@code packageName} is an apex package. */ abstract boolean isApexPackage(String packageName); /** * Retrieves information about an apexd staged session i.e. the internal state used by apexd to * track the different states of a session. * * @param sessionId the identifier of the session. * @return an ApexSessionInfo object, or null if the session is not known. */ @Nullable abstract ApexSessionInfo getStagedSessionInfo(int sessionId); /** * Submit a staged session to apex service. This causes the apex service to perform some initial * verification and accept or reject the session. Submitting a session successfully is not * enough for it to be activated at the next boot, the caller needs to call * {@link #markStagedSessionReady(int)}. * * @param sessionId the identifier of the {@link PackageInstallerSession} being submitted. * @param childSessionIds if {@code sessionId} is a multi-package session, this should contain * an array of identifiers of all the child sessions. Otherwise it should * be an empty array. * @param apexInfoList this is an output parameter, which needs to be initialized by tha caller * and will be filled with a list of {@link ApexInfo} objects, each of which * contains metadata about one of the packages being submitted as part of * the session. * @return whether the submission of the session was successful. */ abstract boolean submitStagedSession( int sessionId, @NonNull int[] childSessionIds, @NonNull ApexInfoList apexInfoList); /** * Mark a staged session previously submitted using {@code submitStagedSession} as ready to be * applied at next reboot. * * @param sessionId the identifier of the {@link PackageInstallerSession} being marked as ready. * @return true upon success, false if the session is unknown. */ abstract boolean markStagedSessionReady(int sessionId); /** * Marks a staged session as successful. * * <p>Only activated session can be marked as successful. * * @param sessionId the identifier of the {@link PackageInstallerSession} being marked as * successful. */ 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. */ abstract boolean isApexSupported(); /** * Abandons the (only) active session previously submitted. * * @return {@code true} upon success, {@code false} if any remote exception occurs */ abstract boolean abortActiveSession(); /** * Uninstalls given {@code apexPackage}. * * <p>NOTE. Device must be rebooted in order for uninstall to take effect. * * @param apexPackagePath package to uninstall. * @return {@code true} upon successful uninstall, {@code false} otherwise. */ abstract boolean uninstallApex(String apexPackagePath); /** * 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. */ abstract void dump(PrintWriter pw, @Nullable String packageName); @IntDef( flag = true, prefix = { "MATCH_"}, value = {MATCH_ACTIVE_PACKAGE, MATCH_FACTORY_PACKAGE}) @Retention(RetentionPolicy.SOURCE) @interface PackageInfoFlags{} /** * An implementation of {@link ApexManager} that should be used in case device supports updating * APEX packages. */ private static class ApexManagerImpl extends ApexManager { private final IApexService mApexService; private final Context mContext; private final Object mLock = new Object(); Loading @@ -70,35 +233,37 @@ class ApexManager { @GuardedBy("mLock") private List<PackageInfo> mAllPackagesCache; ApexManager(Context context) { ApexManagerImpl(Context context, IApexService apexService) { 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"); 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; } 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{} /** * 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() { if (!isApexSupported()) return; mContext.registerReceiver(new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { onBootCompleted(); populateAllPackagesCacheIfNeeded(); mContext.unregisterReceiver(this); } }, new IntentFilter(Intent.ACTION_BOOT_COMPLETED)); Loading Loading @@ -141,7 +306,7 @@ class ApexManager { } factoryPackagesSet.add(pkg.packageName); } } catch (PackageParserException pe) { } catch (PackageParser.PackageParserException pe) { throw new IllegalStateException("Unable to parse: " + ai, pe); } } Loading @@ -152,20 +317,8 @@ class ApexManager { } } /** * Retrieves information about an APEX package. * * @param packageName the package name to look for. Note that this is the package name reported * in the APK container manifest (i.e. AndroidManifest.xml), which might * differ from the one reported in the APEX manifest (i.e. * apex_manifest.json). * @param flags the type of package to return. This may match to active packages * and factory (pre-installed) packages. * @return a PackageInfo object with the information about the package, or null if the package * is not found. */ @Override @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; Loading @@ -181,14 +334,8 @@ class ApexManager { return null; } /** * Retrieves information about all active APEX packages. * * @return a List of PackageInfo object, each one containing information about a different * active package. */ @Override List<PackageInfo> getActivePackages() { if (!isApexSupported()) return Collections.emptyList(); populateAllPackagesCacheIfNeeded(); return mAllPackagesCache .stream() Loading @@ -196,14 +343,8 @@ class ApexManager { .collect(Collectors.toList()); } /** * Retrieves information about all active pre-installed APEX packages. * * @return a List of PackageInfo object, each one containing information about a different * active pre-installed package. */ @Override List<PackageInfo> getFactoryPackages() { if (!isApexSupported()) return Collections.emptyList(); populateAllPackagesCacheIfNeeded(); return mAllPackagesCache .stream() Loading @@ -211,14 +352,8 @@ class ApexManager { .collect(Collectors.toList()); } /** * Retrieves information about all inactive APEX packages. * * @return a List of PackageInfo object, each one containing information about a different * inactive package. */ @Override List<PackageInfo> getInactivePackages() { if (!isApexSupported()) return Collections.emptyList(); populateAllPackagesCacheIfNeeded(); return mAllPackagesCache .stream() Loading @@ -226,12 +361,7 @@ class ApexManager { .collect(Collectors.toList()); } /** * Checks if {@code packageName} is an apex package. * * @param packageName package to check. * @return {@code true} if {@code packageName} is an apex package. */ @Override boolean isApexPackage(String packageName) { if (!isApexSupported()) return false; populateAllPackagesCacheIfNeeded(); Loading @@ -243,15 +373,8 @@ class ApexManager { return false; } /** * Retrieves information about an apexd staged session i.e. the internal state used by apexd to * track the different states of a session. * * @param sessionId the identifier of the session. * @return an ApexSessionInfo object, or null if the session is not known. */ @Override @Nullable ApexSessionInfo getStagedSessionInfo(int sessionId) { if (!isApexSupported()) return null; try { ApexSessionInfo apexSessionInfo = mApexService.getStagedSessionInfo(sessionId); if (apexSessionInfo.isUnknown) { Loading @@ -264,25 +387,9 @@ class ApexManager { } } /** * Submit a staged session to apex service. This causes the apex service to perform some initial * verification and accept or reject the session. Submitting a session successfully is not * enough for it to be activated at the next boot, the caller needs to call * {@link #markStagedSessionReady(int)}. * * @param sessionId the identifier of the {@link PackageInstallerSession} being submitted. * @param childSessionIds if {@code sessionId} is a multi-package session, this should contain * an array of identifiers of all the child sessions. Otherwise it should * be an empty array. * @param apexInfoList this is an output parameter, which needs to be initialized by tha caller * and will be filled with a list of {@link ApexInfo} objects, each of which * contains metadata about one of the packages being submitted as part of * the session. * @return whether the submission of the session was successful. */ @Override boolean submitStagedSession( int sessionId, @NonNull int[] childSessionIds, @NonNull ApexInfoList apexInfoList) { if (!isApexSupported()) return false; try { return mApexService.submitStagedSession(sessionId, childSessionIds, apexInfoList); } catch (RemoteException re) { Loading @@ -291,15 +398,8 @@ class ApexManager { } } /** * Mark a staged session previously submitted using {@code submitStagedSession} as ready to be * applied at next reboot. * * @param sessionId the identifier of the {@link PackageInstallerSession} being marked as ready. * @return true upon success, false if the session is unknown. */ @Override boolean markStagedSessionReady(int sessionId) { if (!isApexSupported()) return false; try { return mApexService.markStagedSessionReady(sessionId); } catch (RemoteException re) { Loading @@ -308,44 +408,27 @@ class ApexManager { } } /** * Marks a staged session as successful. * * <p>Only activated session can be marked as successful. * * @param sessionId the identifier of the {@link PackageInstallerSession} being marked as * successful. */ @Override 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. // 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); } } /** * Whether the current device supports the management of APEX packages. * * @return true if APEX packages can be managed on this device, false otherwise. */ @Override boolean isApexSupported() { return ApexProperties.updatable().orElse(false); return true; } /** * Abandons the (only) active session previously submitted. * * @return {@code true} upon success, {@code false} if any remote exception occurs */ @Override boolean abortActiveSession() { if (!isApexSupported()) return false; try { mApexService.abortActiveSession(); return true; Loading @@ -355,16 +438,8 @@ class ApexManager { } } /** * Uninstalls given {@code apexPackage}. * * <p>NOTE. Device must be rebooted in order for uninstall to take effect. * * @param apexPackagePath package to uninstall. * @return {@code true} upon successful uninstall, {@code false} otherwise. */ @Override boolean uninstallApex(String apexPackagePath) { if (!isApexSupported()) return false; try { mApexService.unstagePackages(Collections.singletonList(apexPackagePath)); return true; Loading @@ -373,31 +448,11 @@ class ApexManager { } } /** * 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; } /** * 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 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( Loading @@ -422,15 +477,8 @@ class ApexManager { 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. */ @Override void dump(PrintWriter pw, @Nullable String packageName) { if (!isApexSupported()) return; final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ", 120); try { populateAllPackagesCacheIfNeeded(); Loading Loading @@ -474,9 +522,83 @@ class ApexManager { 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 } } }
services/core/java/com/android/server/pm/PackageManagerService.java +1 −1 Original line number Diff line number Diff line Loading @@ -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