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

Commit 4cf478ee authored by Rohit Goyal's avatar Rohit Goyal Committed by Android (Google) Code Review
Browse files

Merge "Update ActivityStarter to handle the case for starting unarchival for...

Merge "Update ActivityStarter to handle the case for starting unarchival for archived app." into main
parents f2b20054 ac22f794
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -48,6 +48,7 @@ import com.android.internal.util.function.pooled.PooledLambda;
import com.android.permission.persistence.RuntimePermissionsState;
import com.android.server.pm.Installer.LegacyDexoptDisabledException;
import com.android.server.pm.KnownPackages;
import com.android.server.pm.PackageArchiver;
import com.android.server.pm.PackageList;
import com.android.server.pm.PackageSetting;
import com.android.server.pm.dex.DynamicCodeLogger;
@@ -1442,4 +1443,10 @@ public abstract class PackageManagerInternal {
     */
    public abstract void sendPackageDataClearedBroadcast(@NonNull String packageName,
            int uid, int userId, boolean isRestore, boolean isInstantApp);

    /**
     * Returns an instance of {@link PackageArchiver} to be used for archiving related operations.
     */
    @NonNull
    public abstract PackageArchiver getPackageArchiver();
}
+131 −1
Original line number Diff line number Diff line
@@ -16,6 +16,10 @@

package com.android.server.pm;

import static android.app.ActivityManager.START_ABORTED;
import static android.app.ActivityManager.START_CLASS_NOT_FOUND;
import static android.app.ActivityManager.START_PERMISSION_DENIED;
import static android.app.ActivityManager.START_SUCCESS;
import static android.app.AppOpsManager.MODE_IGNORED;
import static android.app.ComponentOptions.MODE_BACKGROUND_ACTIVITY_START_DENIED;
import static android.content.pm.ArchivedActivityInfo.bytesFromBitmap;
@@ -34,7 +38,10 @@ import android.annotation.UserIdInt;
import android.app.ActivityManager;
import android.app.AppOpsManager;
import android.app.BroadcastOptions;
import android.content.ComponentName;
import android.content.Context;
import android.content.IIntentReceiver;
import android.content.IIntentSender;
import android.content.Intent;
import android.content.IntentSender;
import android.content.pm.ApplicationInfo;
@@ -58,6 +65,7 @@ import android.graphics.drawable.LayerDrawable;
import android.os.Binder;
import android.os.Bundle;
import android.os.Environment;
import android.os.IBinder;
import android.os.ParcelableException;
import android.os.Process;
import android.os.SELinux;
@@ -71,6 +79,7 @@ import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.pm.pkg.ArchiveState;
import com.android.server.pm.pkg.ArchiveState.ArchiveActivityInfo;
import com.android.server.pm.pkg.PackageState;
import com.android.server.pm.pkg.PackageStateInternal;
import com.android.server.pm.pkg.PackageUserState;
import com.android.server.pm.pkg.PackageUserStateInternal;
@@ -185,6 +194,113 @@ public class PackageArchiver {
                        });
    }

    /**
     * Starts unarchival for the package corresponding to the startActivity intent. Note that this
     * will work only if the caller is the default/Home Launcher or if activity is started via Shell
     * identity.
     */
    @NonNull
    public int requestUnarchiveOnActivityStart(@Nullable Intent intent,
            @Nullable String callerPackageName, int userId, int callingUid) {
        String packageName = getPackageNameFromIntent(intent);
        if (packageName == null) {
            Slog.e(TAG, "packageName cannot be null for unarchival!");
            return START_CLASS_NOT_FOUND;
        }
        if (callerPackageName == null) {
            Slog.e(TAG, "callerPackageName cannot be null for unarchival!");
            return START_CLASS_NOT_FOUND;
        }
        if (!isCallingPackageValid(callerPackageName, callingUid, userId)) {
            // Return early as the calling UID does not match caller package's UID.
            return START_CLASS_NOT_FOUND;
        }
        String currentLauncherPackageName = getCurrentLauncherPackageName(userId);
        if ((currentLauncherPackageName == null || !callerPackageName.equals(
                currentLauncherPackageName)) && callingUid != Process.SHELL_UID) {
            // TODO(b/311619990): Remove dependency on SHELL_UID for testing
            Slog.e(TAG, TextUtils.formatSimple(
                    "callerPackageName: %s does not qualify for archival of package: " + "%s!",
                    callerPackageName, packageName));
            return START_PERMISSION_DENIED;
        }
        // TODO(b/302114464): Handle edge cases & also divert to a dialog based on
        //  permissions + compat options
        Slog.i(TAG, TextUtils.formatSimple("Unarchival is starting for: %s", packageName));
        try {
            final IIntentSender.Stub mLocalSender = new IIntentSender.Stub() {
                @Override
                public void send(int code, Intent intent, String resolvedType,
                        IBinder allowlistToken,
                        IIntentReceiver finishedReceiver, String requiredPermission,
                        Bundle options) {
                    // TODO(b/302114464): Handle intent sender status codes
                }
            };

            requestUnarchive(packageName, callerPackageName,
                    new IntentSender((IIntentSender) mLocalSender), UserHandle.of(userId));
        } catch (Throwable t) {
            Slog.e(TAG, TextUtils.formatSimple(
                    "Unexpected error occurred while unarchiving package %s: %s.", packageName,
                    t.getLocalizedMessage()));
            return START_ABORTED;
        }
        return START_SUCCESS;
    }

    /**
     * Returns true if the componentName targeted by the intent corresponds to that of an archived
     * app.
     */
    public boolean isIntentResolvedToArchivedApp(Intent intent, int userId) {
        String packageName = getPackageNameFromIntent(intent);
        if (packageName == null || intent.getComponent() == null) {
            return false;
        }
        PackageState packageState = mPm.snapshotComputer().getPackageStateInternal(packageName);
        if (packageState == null) {
            return false;
        }
        PackageUserState userState = packageState.getUserStateOrDefault(userId);
        if (!PackageArchiver.isArchived(userState)) {
            return false;
        }
        List<ArchiveState.ArchiveActivityInfo> archiveActivityInfoList =
                userState.getArchiveState().getActivityInfos();
        for (int i = 0; i < archiveActivityInfoList.size(); i++) {
            if (archiveActivityInfoList.get(i)
                    .getOriginalComponentName().equals(intent.getComponent())) {
                return true;
            }
        }
        Slog.e(TAG, TextUtils.formatSimple(
                "Package: %s is archived but component to start main activity"
                        + " cannot be found!", packageName));
        return false;
    }

    @Nullable
    private String getCurrentLauncherPackageName(int userId) {
        ComponentName defaultLauncherComponent = mPm.snapshotComputer().getDefaultHomeActivity(
                userId);
        if (defaultLauncherComponent != null) {
            return defaultLauncherComponent.getPackageName();
        }
        return null;
    }

    private boolean isCallingPackageValid(String callingPackage, int callingUid, int userId) {
        int packageUid;
        packageUid = mPm.snapshotComputer().getPackageUid(callingPackage, 0L, userId);
        if (packageUid != callingUid) {
            Slog.w(TAG, TextUtils.formatSimple("Calling package: %s does not belong to uid: %d",
                    callingPackage, callingUid));
            return false;
        }
        return true;
    }

    /** Creates archived state for the package and user. */
    private CompletableFuture<ArchiveState> createArchiveState(String packageName, int userId)
            throws PackageManager.NameNotFoundException {
@@ -403,7 +519,7 @@ public class PackageArchiver {
        Computer snapshot = mPm.snapshotComputer();
        int userId = userHandle.getIdentifier();
        int binderUid = Binder.getCallingUid();
        if (!PackageManagerServiceUtils.isRootOrShell(binderUid)) {
        if (!PackageManagerServiceUtils.isSystemOrRootOrShell(binderUid)) {
            verifyCaller(snapshot.getPackageUid(callerPackageName, 0, userId), binderUid);
        }
        snapshot.enforceCrossUserPermission(binderUid, userId, true, true,
@@ -780,6 +896,20 @@ public class PackageArchiver {
        return bytesFromBitmap(BitmapFactory.decodeFile(path.toString()));
    }

    @Nullable
    private static String getPackageNameFromIntent(@Nullable Intent intent) {
        if (intent == null) {
            return null;
        }
        if (intent.getPackage() != null) {
            return intent.getPackage();
        }
        if (intent.getComponent() != null) {
            return intent.getComponent().getPackageName();
        }
        return null;
    }

    /**
     * Creates serializable archived activities from existing ArchiveState.
     */
+5 −0
Original line number Diff line number Diff line
@@ -6975,6 +6975,11 @@ public class PackageManagerService implements PackageSender, TestUtilityService
            return mInstallerService.getHistoricalSessions(userId);
        }

        @Override
        public PackageArchiver getPackageArchiver() {
            return mInstallerService.mPackageArchiver;
        }

        @Override
        public void sendPackageRestartedBroadcast(@NonNull String packageName,
                int uid, @Intent.Flags int flags) {
+13 −0
Original line number Diff line number Diff line
@@ -103,6 +103,7 @@ import android.content.IntentSender;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.AuxiliaryResolveInfo;
import android.content.pm.Flags;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.content.pm.ResolveInfo;
@@ -128,6 +129,7 @@ import com.android.internal.app.IVoiceInteractor;
import com.android.internal.protolog.common.ProtoLog;
import com.android.server.am.PendingIntentRecord;
import com.android.server.pm.InstantAppResolver;
import com.android.server.pm.PackageArchiver;
import com.android.server.power.ShutdownCheckPoints;
import com.android.server.statusbar.StatusBarManagerInternal;
import com.android.server.uri.NeededUriGrants;
@@ -958,6 +960,17 @@ class ActivityStarter {
            }
        }

        if (Flags.archiving()) {
            PackageArchiver packageArchiver = mService
                    .getPackageManagerInternalLocked()
                    .getPackageArchiver();
            if (packageArchiver.isIntentResolvedToArchivedApp(intent, mRequest.userId)) {
                return packageArchiver
                        .requestUnarchiveOnActivityStart(
                                intent, callingPackage, mRequest.userId, realCallingUid);
            }
        }

        final int launchFlags = intent.getFlags();
        if ((launchFlags & Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0 && sourceRecord != null) {
            // Transfer the result target from the source activity to the new one being started,