Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3c79b983 authored by Nextbit's avatar Nextbit Committed by Gerrit Code Review
Browse files

PackageManager: Add configuration APIs for pre-launch checks

This change replaces overlays with an audited set() API, allowing
application with INTERCEPT_PACKAGE_LAUNCH permission to bootstrap
themselves.

Additionally, checks have been added to ensure that the custom prelaunch
check activity always resolves to a valid target.

Change-Id: I7f6be647fde3ce4ed699e6abfbe0392176ec96d3
(cherry picked from commit c1064a06)
parent b0fb2293
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -431,6 +431,9 @@ interface IPackageManager {
    void setComponentProtectedSetting(in ComponentName componentName, in boolean newState,
            int userId);

    /** Package interception */
    void setPreLaunchCheckActivity(in ComponentName componentName);
    void addPreLaunchCheckPackage(String packageName);
    void removePreLaunchCheckPackage(String packageName);
    void clearPreLaunchCheckPackages();
}
+103 −36
Original line number Diff line number Diff line
@@ -516,9 +516,7 @@ public class PackageManagerService extends IPackageManager.Stub {
    private ThemeConfig mBootThemeConfig;
    final ActivityInfo mPreLaunchCheckActivity = new ActivityInfo();
    final ResolveInfo mPreLaunchCheckResolveInfo = new ResolveInfo();
    ComponentName mPreLaunchCheckPackagesComponentName;
    ComponentName mCustomPreLaunchComponentName;
    private Set<String> mPreLaunchCheckPackages =
            Collections.synchronizedSet(new HashSet<String>());
@@ -1267,15 +1265,6 @@ public class PackageManagerService extends IPackageManager.Stub {
                startTime = SystemClock.uptimeMillis();
                String customPreLaunchCheckActivity = Resources.getSystem().getString(
                        R.string.config_prelaunchcheckactivity);
                if (TextUtils.isEmpty(customPreLaunchCheckActivity)) {
                    customPreLaunchCheckActivity = null;
                } else {
                    mCustomPreLaunchComponentName = ComponentName.unflattenFromString(
                            customPreLaunchCheckActivity);
                }
                EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SYSTEM_SCAN_START,
                        startTime);
@@ -2918,26 +2907,54 @@ public class PackageManagerService extends IPackageManager.Stub {
    }
    private ResolveInfo findPreLaunchCheckResolve(Intent intent, ResolveInfo rInfo, int userId) {
        if (mPreLaunchCheckPackagesComponentName == null) {
        final boolean cachedPreLaunchCheckPackagesReplaced;
        final ResolveInfo cachedPreLaunchCheckResolveInfo;
        // Retrieve a consistent read on the prelaunch configuration
        synchronized (mPackages) {
            cachedPreLaunchCheckPackagesReplaced = mPreLaunchCheckPackagesReplaced;
            cachedPreLaunchCheckResolveInfo = new ResolveInfo(mPreLaunchCheckResolveInfo);
        }
        // Skip if the prelaunch check is not set (using setPreLaunchCheckActivity).
        if (!cachedPreLaunchCheckPackagesReplaced) {
            return rInfo;
        }
        String packageName = rInfo.activityInfo.packageName;
        // If pre launch check has been enabled for this pacakge, return the appropriate
        // If pre launch check has been enabled for this package, return the appropriate
        // resolve info.
        if (!mPreLaunchCheckPackages.contains(packageName)) {
            return rInfo;
        }
        // Only pre-check for intents that show up in the Launcher, if the intent originates
        // Only pre-check for intents that show up in the Launcher. If the intent originates
        // elsewhere, ignore it.
        if (!intent.hasCategory(Intent.CATEGORY_LAUNCHER)) {
            return rInfo;
        }
        // Make sure that the package which handles the preLaunchChecks is still installed.
        ActivityInfo preLaunchCheckActivity = cachedPreLaunchCheckResolveInfo.activityInfo;
        if (preLaunchCheckActivity != null &&
                isPackageAvailable(preLaunchCheckActivity.packageName, userId) == false) {
            return rInfo;
        }
        // Make sure the package that handles preLaunchCheck is not disabled.
        synchronized (mPackages) {
            PackageSetting ps = mSettings.mPackages.get(preLaunchCheckActivity.packageName);
            int enableState = ps.getCurrentEnabledStateLPr(
                    preLaunchCheckActivity.name, userId);
            if (enableState == PackageManager.COMPONENT_ENABLED_STATE_DISABLED ||
                    enableState == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER) {
                return rInfo;
            }
        }
        if (userId != 0) {
            ResolveInfo ri;
            ri = new ResolveInfo(mPreLaunchCheckResolveInfo);
            ri = new ResolveInfo(cachedPreLaunchCheckResolveInfo);
            ri.activityInfo = new ActivityInfo(ri.activityInfo);
            ri.activityInfo.applicationInfo = new ApplicationInfo(
                    ri.activityInfo.applicationInfo);
@@ -2947,10 +2964,11 @@ public class PackageManagerService extends IPackageManager.Stub {
                    ri.activityInfo.targetActivity);
            return ri;
        }
        // Save the target component since we are doing the redirection here.
        mPreLaunchCheckResolveInfo.targetComponentName = new ComponentName(
        // Set the new target component before returning the redirection.
        cachedPreLaunchCheckResolveInfo.targetComponentName = new ComponentName(
                rInfo.activityInfo.packageName, rInfo.activityInfo.name);
        return mPreLaunchCheckResolveInfo;
        return cachedPreLaunchCheckResolveInfo;
    }
    private ResolveInfo chooseBestActivity(Intent intent, String resolvedType,
@@ -4546,11 +4564,6 @@ public class PackageManagerService extends IPackageManager.Stub {
                    mResolveComponentName = new ComponentName(
                            mAndroidApplication.packageName, mResolveActivity.name);
                }
                if (!mPreLaunchCheckPackagesReplaced) {
                    // If a default pre launch check activity is defined, define it here.
                    Log.d(TAG, "No custom and no default Pre Launch Check activity defined");
                }
            }
        }
@@ -6026,28 +6039,38 @@ public class PackageManagerService extends IPackageManager.Stub {
        }
    }
    /**
     * Matches scanned packages with the requested PreLaunchCheckActivity, and prepares
     * mPreLaunchCheckResolveInfo.
     *
     * - mCustomPreLaunchComponentName holds the requested ComponentName.  This
     *   value may refer to a package that is not yet available (not yet installed or
     *   not yet detected).
     * - When mPreLaunchCheckPackagesReplaced is true, it indicates that
     *   mPreLaunchCheckResolveInfo properly installed.
     */
    private void setUpCustomPreLaunchCheckActivity(PackageParser.Package pkg) {
        synchronized (mPackages) {
            mPreLaunchCheckPackagesReplaced = true;
            // Set up information for custom user intent resolution activity.
            mPreLaunchCheckActivity.applicationInfo = pkg.applicationInfo;
            mPreLaunchCheckActivity.name = mCustomPreLaunchComponentName.getClassName();
            mPreLaunchCheckActivity.packageName = pkg.applicationInfo.packageName;
            mPreLaunchCheckActivity.processName = pkg.applicationInfo.packageName;
            mPreLaunchCheckActivity.theme = com.android.internal.R.style.Theme_Holo_Dialog_Alert;
            mPreLaunchCheckActivity.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
            mPreLaunchCheckActivity.flags = ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS |
            ActivityInfo preLaunchCheckActivity = new ActivityInfo();
            preLaunchCheckActivity.applicationInfo = pkg.applicationInfo;
            preLaunchCheckActivity.name = mCustomPreLaunchComponentName.getClassName();
            preLaunchCheckActivity.packageName = pkg.applicationInfo.packageName;
            preLaunchCheckActivity.processName = pkg.applicationInfo.packageName;
            preLaunchCheckActivity.theme = com.android.internal.R.style.Theme_Holo_Dialog_Alert;
            preLaunchCheckActivity.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
            preLaunchCheckActivity.flags = ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS |
                    ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS;
            mPreLaunchCheckActivity.exported = true;
            mPreLaunchCheckActivity.enabled = true;
            preLaunchCheckActivity.exported = true;
            preLaunchCheckActivity.enabled = true;
            mPreLaunchCheckResolveInfo.activityInfo = mPreLaunchCheckActivity;
            mPreLaunchCheckResolveInfo.activityInfo = preLaunchCheckActivity;
            mPreLaunchCheckResolveInfo.priority = 0;
            mPreLaunchCheckResolveInfo.preferredOrder = 0;
            mPreLaunchCheckResolveInfo.match = 0;
            mPreLaunchCheckPackagesComponentName = mCustomPreLaunchComponentName;
            Slog.i(TAG, "Replacing default Pre Launch Activity with custom activity: " +
                    mPreLaunchCheckPackagesComponentName);
                    mCustomPreLaunchComponentName);
        }
    }
@@ -12612,6 +12635,42 @@ public class PackageManagerService extends IPackageManager.Stub {
        return true;
    }
    /**
     * Configures the prelaunch check activity.
     *
     * When called with a null componentName, the prelaunch check is disabled.
     */
    @Override
    public final void setPreLaunchCheckActivity(ComponentName componentName) {
        mContext.enforceCallingOrSelfPermission(
                android.Manifest.permission.INTERCEPT_PACKAGE_LAUNCH, null);
        synchronized (mPackages) {
            mCustomPreLaunchComponentName = componentName;
            if (componentName == null) {
                // When componentName is null, disable the custom activity.
                Slog.i(TAG, "Pre Launch Check: Removed");
                // Note: setUpCustomPreLaunchCheckActivity is responsible for
                // setting this boolean true.  This helps handle the situation where
                // the package has not yet been scanned by the system or installed.
                mPreLaunchCheckPackagesReplaced = false;
            } else {
                // Check if the package is already installed.
                // If not, depend on scanPackageLI() to discover the package.
                String pkgName = componentName.getPackageName();
                PackageParser.Package pkg = mPackages.get(pkgName);
                if (pkg != null) {
                    setUpCustomPreLaunchCheckActivity(pkg);
                } else {
                    Slog.i(TAG, "Pre Launch Check: Pending installation of " + pkgName);
                }
            }
        }
    }
    @Override
    public final void addPreLaunchCheckPackage(String packageName) {
        mContext.enforceCallingOrSelfPermission(
@@ -12626,6 +12685,14 @@ public class PackageManagerService extends IPackageManager.Stub {
        mPreLaunchCheckPackages.remove(packageName);
    }
    @Override
    public final void clearPreLaunchCheckPackages() {
        mContext.enforceCallingOrSelfPermission(
                android.Manifest.permission.INTERCEPT_PACKAGE_LAUNCH, null);
        Slog.i(TAG, "Clearing Pre Launch Check Packages.");
        mPreLaunchCheckPackages.clear();
    }
    public boolean isStorageLow() {
        final long token = Binder.clearCallingIdentity();
        try {