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

Commit 80855e15 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Implement new ephemeral resolver design" into nyc-mr1-dev

parents 05bce15d fea1b776
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -4313,6 +4313,14 @@ public class Intent implements Parcelable, Cloneable {
     */
    public static final int FLAG_DEBUG_TRIAGED_MISSING = 0x00000100;

    /**
     * Internal flag used to indicate ephemeral applications should not be
     * considered when resolving the intent.
     *
     * @hide
     */
    public static final int FLAG_IGNORE_EPHEMERAL = 0x00000200;

    /**
     * If set, the new activity is not kept in the history stack.  As soon as
     * the user navigates away from it, the activity is finished.  This may also
+0 −6
Original line number Diff line number Diff line
@@ -67,12 +67,6 @@ public class ResolveInfo implements Parcelable {
     */
    public EphemeralResolveInfo ephemeralResolveInfo;

    /**
     * A ResolveInfo that points at the ephemeral installer.
     * @hide
     */
    public ResolveInfo ephemeralInstaller;

    /**
     * The IntentFilter that was matched for this ResolveInfo.
     */
+61 −29
Original line number Diff line number Diff line
@@ -103,6 +103,7 @@ import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
import android.os.PowerManagerInternal;
import android.os.Process;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.UserHandle;
@@ -132,6 +133,9 @@ class ActivityStarter {
    private static final String TAG_CONFIGURATION = TAG + POSTFIX_CONFIGURATION;
    private static final String TAG_USER_LEAVING = TAG + POSTFIX_USER_LEAVING;

    // TODO b/30204367 remove when the platform fully supports ephemeral applications
    private static final boolean USE_DEFAULT_EPHEMERAL_LAUNCHER = false;

    private final ActivityManagerService mService;
    private final ActivityStackSupervisor mSupervisor;
    private ActivityStartInterceptor mInterceptor;
@@ -456,39 +460,13 @@ class ActivityStarter {
        // starts either the intent we resolved here [on install error] or the ephemeral
        // app [on install success].
        if (rInfo != null && rInfo.ephemeralResolveInfo != null) {
            // Create a pending intent to start the intent resolved here.
            final IIntentSender failureTarget = mService.getIntentSenderLocked(
                    ActivityManager.INTENT_SENDER_ACTIVITY, callingPackage,
                    Binder.getCallingUid(), userId, null, null, 0, new Intent[]{ intent },
                    new String[]{ resolvedType },
                    PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT
                            | PendingIntent.FLAG_IMMUTABLE, null);

            // Create a pending intent to start the ephemeral application; force it to be
            // directed to the ephemeral package.
            ephemeralIntent.setPackage(rInfo.ephemeralResolveInfo.getPackageName());
            final IIntentSender ephemeralTarget = mService.getIntentSenderLocked(
                    ActivityManager.INTENT_SENDER_ACTIVITY, callingPackage,
                    Binder.getCallingUid(), userId, null, null, 0, new Intent[]{ ephemeralIntent },
                    new String[]{ resolvedType },
                    PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT
                            | PendingIntent.FLAG_IMMUTABLE, null);

            int flags = intent.getFlags();
            intent = new Intent();
            intent.setFlags(flags
                    | Intent.FLAG_ACTIVITY_NEW_TASK
                    | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
            intent.putExtra(Intent.EXTRA_PACKAGE_NAME,
                    rInfo.ephemeralResolveInfo.getPackageName());
            intent.putExtra(Intent.EXTRA_EPHEMERAL_FAILURE, new IntentSender(failureTarget));
            intent.putExtra(Intent.EXTRA_EPHEMERAL_SUCCESS, new IntentSender(ephemeralTarget));

            intent = buildEphemeralInstallerIntent(intent, ephemeralIntent,
                    rInfo.ephemeralResolveInfo.getPackageName(), callingPackage, resolvedType,
                    userId);
            resolvedType = null;
            callingUid = realCallingUid;
            callingPid = realCallingPid;

            rInfo = rInfo.ephemeralInstaller;
            aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags, null /*profilerInfo*/);
        }

@@ -543,6 +521,60 @@ class ActivityStarter {
        return err;
    }

    /**
     * Builds and returns an intent to launch the ephemeral installer.
     */
    private Intent buildEphemeralInstallerIntent(Intent launchIntent, Intent origIntent,
            String ephemeralPackage, String callingPackage, String resolvedType, int userId) {
        final Intent nonEphemeralIntent = new Intent(origIntent);
        nonEphemeralIntent.setFlags(nonEphemeralIntent.getFlags() | Intent.FLAG_IGNORE_EPHEMERAL);
        // Intent that is launched if the ephemeral package couldn't be installed
        // for any reason.
        final IIntentSender failureIntentTarget = mService.getIntentSenderLocked(
                ActivityManager.INTENT_SENDER_ACTIVITY, callingPackage,
                Binder.getCallingUid(), userId, null /*token*/, null /*resultWho*/, 1,
                new Intent[]{ nonEphemeralIntent }, new String[]{ resolvedType },
                PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT
                | PendingIntent.FLAG_IMMUTABLE, null /*bOptions*/);

        final Intent ephemeralIntent;
        if (USE_DEFAULT_EPHEMERAL_LAUNCHER) {
            // Force the intent to be directed to the ephemeral package
            ephemeralIntent = new Intent(origIntent);
            ephemeralIntent.setPackage(ephemeralPackage);
        } else {
            // Success intent goes back to the installer
            // TODO; do we need any extras for the installer?
            ephemeralIntent = new Intent(launchIntent);
            ephemeralIntent.setData(null);
        }

        // Intent that is eventually launched if the ephemeral package was
        // installed successfully. This will actually be launched by a platform
        // broadcast receiver.
        final IIntentSender successIntentTarget = mService.getIntentSenderLocked(
                ActivityManager.INTENT_SENDER_ACTIVITY, callingPackage,
                Binder.getCallingUid(), userId, null /*token*/, null /*resultWho*/, 0,
                new Intent[]{ ephemeralIntent }, new String[]{ resolvedType },
                PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT
                | PendingIntent.FLAG_IMMUTABLE, null /*bOptions*/);

        // Finally build the actual intent to launch the ephemeral installer
        int flags = launchIntent.getFlags();
        final Intent intent = new Intent();
        intent.setFlags(flags
                | Intent.FLAG_ACTIVITY_NEW_TASK
                | Intent.FLAG_ACTIVITY_CLEAR_TASK
                | Intent.FLAG_ACTIVITY_NO_HISTORY
                | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
        intent.putExtra(Intent.EXTRA_PACKAGE_NAME, ephemeralPackage);
        intent.putExtra(Intent.EXTRA_EPHEMERAL_FAILURE, new IntentSender(failureIntentTarget));
        intent.putExtra(Intent.EXTRA_EPHEMERAL_SUCCESS, new IntentSender(successIntentTarget));
        // TODO: Remove when the platform has fully implemented ephemeral apps
        intent.setData(origIntent.getData());
        return intent;
    }

    void postStartActivityUncheckedProcessing(
            ActivityRecord r, int result, int prevFocusedStackId, ActivityRecord sourceRecord,
            ActivityStack targetStack) {
+86 −52
Original line number Diff line number Diff line
@@ -177,6 +177,7 @@ import android.os.Looper;
import android.os.Message;
import android.os.Parcel;
import android.os.ParcelFileDescriptor;
import android.os.PatternMatcher;
import android.os.Process;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
@@ -4725,20 +4726,6 @@ public class PackageManagerService extends IPackageManager.Stub {
            final ResolveInfo bestChoice =
                    chooseBestActivity(intent, resolvedType, flags, query, userId);
            if (isEphemeralAllowed(intent, query, userId)) {
                Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "resolveEphemeral");
                final EphemeralResolveInfo ai =
                        getEphemeralResolveInfo(intent, resolvedType, userId);
                if (ai != null) {
                    if (DEBUG_EPHEMERAL) {
                        Slog.v(TAG, "Returning an EphemeralResolveInfo");
                    }
                    bestChoice.ephemeralInstaller = mEphemeralInstallerInfo;
                    bestChoice.ephemeralResolveInfo = ai;
                }
                Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
            }
            return bestChoice;
        } finally {
            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
@@ -4779,9 +4766,9 @@ public class PackageManagerService extends IPackageManager.Stub {
                false, false, false, userId);
    }
    private boolean isEphemeralAllowed(
            Intent intent, List<ResolveInfo> resolvedActivites, int userId) {
            Intent intent, List<ResolveInfo> resolvedActivities, int userId,
            boolean skipPackageCheck) {
        // Short circuit and return early if possible.
        if (DISABLE_EPHEMERAL_APPS) {
            return false;
@@ -4796,18 +4783,21 @@ public class PackageManagerService extends IPackageManager.Stub {
        if (intent.getComponent() != null) {
            return false;
        }
        if (intent.getPackage() != null) {
        if ((intent.getFlags() & Intent.FLAG_IGNORE_EPHEMERAL) != 0) {
            return false;
        }
        if (!skipPackageCheck && intent.getPackage() != null) {
            return false;
        }
        final boolean isWebUri = hasWebURI(intent);
        if (!isWebUri) {
        if (!isWebUri || intent.getData().getHost() == null) {
            return false;
        }
        // Deny ephemeral apps if the user chose _ALWAYS or _ALWAYS_ASK for intent resolution.
        synchronized (mPackages) {
            final int count = resolvedActivites.size();
            final int count = (resolvedActivities == null ? 0 : resolvedActivities.size());
            for (int n = 0; n < count; n++) {
                ResolveInfo info = resolvedActivites.get(n);
                ResolveInfo info = resolvedActivities.get(n);
                String packageName = info.activityInfo.packageName;
                PackageSetting ps = mSettings.mPackages.get(packageName);
                if (ps != null) {
@@ -4829,19 +4819,19 @@ public class PackageManagerService extends IPackageManager.Stub {
        return true;
    }
    private EphemeralResolveInfo getEphemeralResolveInfo(Intent intent, String resolvedType,
            int userId) {
        final int ephemeralPrefixMask = Global.getInt(mContext.getContentResolver(),
    private static EphemeralResolveInfo getEphemeralResolveInfo(
            Context context, EphemeralResolverConnection resolverConnection, Intent intent,
            String resolvedType, int userId, String packageName) {
        final int ephemeralPrefixMask = Global.getInt(context.getContentResolver(),
                Global.EPHEMERAL_HASH_PREFIX_MASK, DEFAULT_EPHEMERAL_HASH_PREFIX_MASK);
        final int ephemeralPrefixCount = Global.getInt(mContext.getContentResolver(),
        final int ephemeralPrefixCount = Global.getInt(context.getContentResolver(),
                Global.EPHEMERAL_HASH_PREFIX_COUNT, DEFAULT_EPHEMERAL_HASH_PREFIX_COUNT);
        final EphemeralDigest digest = new EphemeralDigest(intent.getData(), ephemeralPrefixMask,
                ephemeralPrefixCount);
        final int[] shaPrefix = digest.getDigestPrefix();
        final byte[][] digestBytes = digest.getDigestBytes();
        final List<EphemeralResolveInfo> ephemeralResolveInfoList =
                mEphemeralResolverConnection.getEphemeralResolveInfoList(
                        shaPrefix, ephemeralPrefixMask);
                resolverConnection.getEphemeralResolveInfoList(shaPrefix, ephemeralPrefixMask);
        if (ephemeralResolveInfoList == null || ephemeralResolveInfoList.size() == 0) {
            // No hash prefix match; there are no ephemeral apps for this domain.
            return null;
@@ -4858,6 +4848,10 @@ public class PackageManagerService extends IPackageManager.Stub {
                if (filters.isEmpty()) {
                    continue;
                }
                if (packageName != null
                        && !packageName.equals(ephemeralApplication.getPackageName())) {
                    continue;
                }
                // We have a domain match; resolve the filters to see if anything matches.
                final EphemeralIntentResolver ephemeralResolver = new EphemeralIntentResolver();
                for (int j = filters.size() - 1; j >= 0; --j) {
@@ -5261,8 +5255,12 @@ public class PackageManagerService extends IPackageManager.Stub {
        }
        // reader
        synchronized (mPackages) {
        boolean sortResult = false;
        boolean addEphemeral = false;
        boolean matchEphemeralPackage = false;
        List<ResolveInfo> result;
        final String pkgName = intent.getPackage();
        synchronized (mPackages) {
            if (pkgName == null) {
                List<CrossProfileIntentFilter> matchingFilters =
                        getMatchingCrossProfileIntentFilters(intent, resolvedType, userId);
@@ -5270,15 +5268,16 @@ public class PackageManagerService extends IPackageManager.Stub {
                ResolveInfo xpResolveInfo  = querySkipCurrentProfileIntents(matchingFilters, intent,
                        resolvedType, flags, userId);
                if (xpResolveInfo != null) {
                    List<ResolveInfo> result = new ArrayList<ResolveInfo>(1);
                    result.add(xpResolveInfo);
                    return filterIfNotSystemUser(result, userId);
                    List<ResolveInfo> xpResult = new ArrayList<ResolveInfo>(1);
                    xpResult.add(xpResolveInfo);
                    return filterIfNotSystemUser(xpResult, userId);
                }
                // Check for results in the current profile.
                List<ResolveInfo> result = mActivities.queryIntent(
                        intent, resolvedType, flags, userId);
                result = filterIfNotSystemUser(result, userId);
                result = filterIfNotSystemUser(mActivities.queryIntent(
                        intent, resolvedType, flags, userId), userId);
                addEphemeral =
                        isEphemeralAllowed(intent, result, userId, false /*skipPackageCheck*/);
                // Check for cross profile results.
                boolean hasNonNegativePriorityResult = hasNonNegativePriority(result);
@@ -5290,7 +5289,7 @@ public class PackageManagerService extends IPackageManager.Stub {
                            Collections.singletonList(xpResolveInfo), userId).size() > 0;
                    if (isVisibleToUser) {
                        result.add(xpResolveInfo);
                        Collections.sort(result, mResolvePrioritySorter);
                        sortResult = true;
                    }
                }
                if (hasWebURI(intent)) {
@@ -5306,29 +5305,62 @@ public class PackageManagerService extends IPackageManager.Stub {
                            // in the result.
                            result.remove(xpResolveInfo);
                        }
                        if (result.size() == 0) {
                        if (result.size() == 0 && !addEphemeral) {
                            result.add(xpDomainInfo.resolveInfo);
                            return result;
                        }
                    } else if (result.size() <= 1) {
                        return result;
                    }
                    result = filterCandidatesWithDomainPreferredActivitiesLPr(intent, flags, result,
                            xpDomainInfo, userId);
                    Collections.sort(result, mResolvePrioritySorter);
                    if (result.size() > 1 || addEphemeral) {
                        result = filterCandidatesWithDomainPreferredActivitiesLPr(
                                intent, flags, result, xpDomainInfo, userId);
                        sortResult = true;
                    }
                return result;
                }
            } else {
                final PackageParser.Package pkg = mPackages.get(pkgName);
                if (pkg != null) {
                return filterIfNotSystemUser(
                    result = filterIfNotSystemUser(
                            mActivities.queryIntentForPackage(
                                    intent, resolvedType, flags, pkg.activities, userId),
                            userId);
                } else {
                    // the caller wants to resolve for a particular package; however, there
                    // were no installed results, so, try to find an ephemeral result
                    addEphemeral = isEphemeralAllowed(
                            intent, null /*result*/, userId, true /*skipPackageCheck*/);
                    matchEphemeralPackage = true;
                    result = new ArrayList<ResolveInfo>();
                }
            return new ArrayList<ResolveInfo>();
            }
        }
        if (addEphemeral) {
            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "resolveEphemeral");
            final EphemeralResolveInfo ai = getEphemeralResolveInfo(
                    mContext, mEphemeralResolverConnection, intent, resolvedType, userId,
                    matchEphemeralPackage ? pkgName : null);
            if (ai != null) {
                if (DEBUG_EPHEMERAL) {
                    Slog.v(TAG, "Adding ephemeral installer to the ResolveInfo list");
                }
                final ResolveInfo ephemeralInstaller = new ResolveInfo(mEphemeralInstallerInfo);
                ephemeralInstaller.ephemeralResolveInfo = ai;
                // make sure this resolver is the default
                ephemeralInstaller.isDefault = true;
                ephemeralInstaller.match = IntentFilter.MATCH_CATEGORY_SCHEME_SPECIFIC_PART
                        | IntentFilter.MATCH_ADJUSTMENT_NORMAL;
                // add a non-generic filter
                ephemeralInstaller.filter = new IntentFilter(intent.getAction());
                ephemeralInstaller.filter.addDataPath(
                        intent.getData().getPath(), PatternMatcher.PATTERN_LITERAL);
                result.add(ephemeralInstaller);
            }
            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
        }
        if (sortResult) {
            Collections.sort(result, mResolvePrioritySorter);
        }
        return result;
    }
    private static class CrossProfileDomainInfo {
        /* ResolveInfo for IntentForwarderActivity to send the intent to the other profile */
@@ -9205,15 +9237,17 @@ public class PackageManagerService extends IPackageManager.Stub {
        mEphemeralInstallerActivity.packageName = pkg.applicationInfo.packageName;
        mEphemeralInstallerActivity.processName = pkg.applicationInfo.packageName;
        mEphemeralInstallerActivity.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
        mEphemeralInstallerActivity.flags = ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS |
                ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS;
        mEphemeralInstallerActivity.flags = ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS
                | ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS;
        mEphemeralInstallerActivity.theme = 0;
        mEphemeralInstallerActivity.exported = true;
        mEphemeralInstallerActivity.enabled = true;
        mEphemeralInstallerInfo.activityInfo = mEphemeralInstallerActivity;
        mEphemeralInstallerInfo.priority = 0;
        mEphemeralInstallerInfo.preferredOrder = 0;
        mEphemeralInstallerInfo.match = 0;
        mEphemeralInstallerInfo.preferredOrder = 1;
        mEphemeralInstallerInfo.isDefault = true;
        mEphemeralInstallerInfo.match = IntentFilter.MATCH_CATEGORY_SCHEME_SPECIFIC_PART
                | IntentFilter.MATCH_ADJUSTMENT_NORMAL;
        if (DEBUG_EPHEMERAL) {
            Slog.d(TAG, "Set ephemeral installer activity: " + mEphemeralInstallerComponent);