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

Commit 6dc1bd35 authored by Rhed Jao's avatar Rhed Jao
Browse files

Support launching apps by package name without visibility

PackageManager#getLaunchIntentForPackage returns null if the caller
is not allowed to query the package. This cl adds a new api using
the same implementation with the #getLaunchIntentForPackage. Instead
of returning the Intent, it returns the IntentSender which is not
restricted by package visibility.

Bug: 175336608
Test: atest android.content.pm.cts.PackageManagerTest
Change-Id: I43524f26b27b2278417dae1a75bcdeb0447b8273
parent 3c2d1e7e
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -12474,6 +12474,7 @@ package android.content.pm {
    method public abstract int getInstantAppCookieMaxBytes();
    method @NonNull public abstract android.content.pm.InstrumentationInfo getInstrumentationInfo(@NonNull android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
    method @Nullable public abstract android.content.Intent getLaunchIntentForPackage(@NonNull String);
    method @NonNull public android.content.IntentSender getLaunchIntentSenderForPackage(@NonNull String);
    method @Nullable public abstract android.content.Intent getLeanbackLaunchIntentForPackage(@NonNull String);
    method @NonNull public java.util.Set<java.lang.String> getMimeGroup(@NonNull String);
    method @NonNull public android.content.pm.ModuleInfo getModuleInfo(@NonNull String, int) throws android.content.pm.PackageManager.NameNotFoundException;
+10 −0
Original line number Diff line number Diff line
@@ -312,6 +312,16 @@ public class ApplicationPackageManager extends PackageManager {
        return intent;
    }

    @Override
    public @NonNull IntentSender getLaunchIntentSenderForPackage(@NonNull String packageName) {
        try {
            return mPM.getLaunchIntentSenderForPackage(packageName, mContext.getPackageName(),
                    mContext.getAttributionTag(), getUserId());
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    @Override
    public int[] getPackageGids(String packageName) throws NameNotFoundException {
        return getPackageGids(packageName, 0);
+3 −0
Original line number Diff line number Diff line
@@ -757,6 +757,9 @@ interface IPackageManager {

    void requestChecksums(in String packageName, boolean includeSplits, int optional, int required, in List trustedInstallers, in IOnChecksumsReadyListener onChecksumsReadyListener, int userId);

    IntentSender getLaunchIntentSenderForPackage(String packageName, String callingPackage,
                String featureId, int userId);

    //------------------------------------------------------------------------
    //
    // The following binder interfaces have been moved to IPermissionManager
+27 −0
Original line number Diff line number Diff line
@@ -4473,12 +4473,17 @@ public abstract class PackageManager {
     * main activity in the category {@link Intent#CATEGORY_LAUNCHER}. Returns
     * <code>null</code> if neither are found.
     *
     * <p>Consider using {@link #getLaunchIntentSenderForPackage(String)} if
     * the caller is not allowed to query for the <code>packageName</code>.
     *
     * @param packageName The name of the package to inspect.
     *
     * @return A fully-qualified {@link Intent} that can be used to launch the
     * main activity in the package. Returns <code>null</code> if the package
     * does not contain such an activity, or if <em>packageName</em> is not
     * recognized.
     *
     * @see #getLaunchIntentSenderForPackage(String)
     */
    public abstract @Nullable Intent getLaunchIntentForPackage(@NonNull String packageName);

@@ -4512,6 +4517,28 @@ public abstract class PackageManager {
    @SuppressWarnings("HiddenAbstractMethod")
    public abstract @Nullable Intent getCarLaunchIntentForPackage(@NonNull String packageName);

    /**
     * Returns an {@link IntentSender} that can be used to launch a front-door activity in a
     * package. This is used, for example, to implement an "open" button when browsing through
     * packages. The current implementation is the same with
     * {@link #getLaunchIntentForPackage(String)}. Instead of returning the {@link Intent}, it
     * returns the {@link IntentSender} which is not restricted by the package visibility.
     *
     * <p>The caller can invoke
     * {@link IntentSender#sendIntent(Context, int, Intent, IntentSender.OnFinished, Handler)}
     * to launch the activity. An {@link IntentSender.SendIntentException} is thrown if the
     * package does not contain such an activity, or if <em>packageName</em> is not recognized.
     *
     * @param packageName The name of the package to inspect.
     * @return Returns a {@link IntentSender} to launch the activity.
     *
     * @see #getLaunchIntentForPackage(String)
     */
    public @NonNull IntentSender getLaunchIntentSenderForPackage(@NonNull String packageName) {
        throw new UnsupportedOperationException("getLaunchIntentSenderForPackage not implemented"
                + "in subclass");
    }

    /**
     * Return an array of all of the POSIX secondary group IDs that have been
     * assigned to the given package.
+52 −0
Original line number Diff line number Diff line
@@ -149,6 +149,7 @@ import android.app.AppOpsManager;
import android.app.ApplicationPackageManager;
import android.app.BroadcastOptions;
import android.app.IActivityManager;
import android.app.PendingIntent;
import android.app.ResourcesManager;
import android.app.admin.IDevicePolicyManager;
import android.app.admin.SecurityLog;
@@ -161,6 +162,7 @@ import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.IIntentReceiver;
import android.content.IIntentSender;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.IntentSender;
@@ -28010,6 +28012,56 @@ public class PackageManagerService extends IPackageManager.Stub
            }
        }
    }
    @Override
    public IntentSender getLaunchIntentSenderForPackage(String packageName, String callingPackage,
            String featureId, int userId) throws RemoteException {
        Objects.requireNonNull(packageName);
        final int callingUid = Binder.getCallingUid();
        enforceCrossUserPermission(callingUid, userId, false /* requireFullPermission */,
                false /* checkShell */, "get launch intent sender for package");
        final int packageUid = getPackageUid(callingPackage, 0 /* flags */, userId);
        if (!UserHandle.isSameApp(callingUid, packageUid)) {
            throw new SecurityException("getLaunchIntentSenderForPackage() from calling uid: "
                    + callingUid + " does not own package: " + callingPackage);
        }
        // Using the same implementation with the #getLaunchIntentForPackage to get the ResolveInfo.
        // Pass the resolveForStart as true in queryIntentActivities to skip the app filtering.
        final Intent intentToResolve = new Intent(Intent.ACTION_MAIN);
        intentToResolve.addCategory(Intent.CATEGORY_INFO);
        intentToResolve.setPackage(packageName);
        String resolvedType = intentToResolve.resolveTypeIfNeeded(mContext.getContentResolver());
        List<ResolveInfo> ris = queryIntentActivitiesInternal(intentToResolve, resolvedType,
                0 /* flags */, 0 /* privateResolveFlags */, callingUid, userId,
                true /* resolveForStart */, false /* allowDynamicSplits */);
        if (ris == null || ris.size() <= 0) {
            intentToResolve.removeCategory(Intent.CATEGORY_INFO);
            intentToResolve.addCategory(Intent.CATEGORY_LAUNCHER);
            intentToResolve.setPackage(packageName);
            resolvedType = intentToResolve.resolveTypeIfNeeded(mContext.getContentResolver());
            ris = queryIntentActivitiesInternal(intentToResolve, resolvedType,
                    0 /* flags */, 0 /* privateResolveFlags */, callingUid, userId,
                    true /* resolveForStart */, false /* allowDynamicSplits */);
        }
        final Intent intent = new Intent(intentToResolve);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        // For the case of empty result, no component name is assigned into the intent. A
        // non-launchable IntentSender which contains the failed intent is created. The
        // SendIntentException is thrown if the IntentSender#sendIntent is invoked.
        if (ris != null && !ris.isEmpty()) {
            intent.setClassName(ris.get(0).activityInfo.packageName,
                    ris.get(0).activityInfo.name);
        }
        final IIntentSender target = ActivityManager.getService().getIntentSenderWithFeature(
                ActivityManager.INTENT_SENDER_ACTIVITY, callingPackage,
                featureId, null /* token */, null /* resultWho */,
                1 /* requestCode */, new Intent[] { intent },
                resolvedType != null ? new String[] { resolvedType } : null,
                PendingIntent.FLAG_IMMUTABLE, null /* bOptions */, userId);
        return new IntentSender(target);
    }
}
interface PackageSender {