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

Commit 2b340a2e authored by Jon Miranda's avatar Jon Miranda Committed by Sunny Goyal
Browse files

Allow cross user SessionCallback support

Bug: 31929647
Test: Manually tests on device and added CTS tests
Change-Id: I083435c12ce56a675ccf2cb5e00c76fbaace6c65
parent d6a69968
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -11224,6 +11224,7 @@ package android.content.pm {
  public class LauncherApps {
    method public java.util.List<android.content.pm.LauncherActivityInfo> getActivityList(String, android.os.UserHandle);
    method @NonNull public java.util.List<android.content.pm.PackageInstaller.SessionInfo> getAllPackageInstallerSessions();
    method @Nullable public android.content.pm.LauncherApps.AppUsageLimit getAppUsageLimit(String, android.os.UserHandle);
    method public android.content.pm.ApplicationInfo getApplicationInfo(@NonNull String, int, @NonNull android.os.UserHandle) throws android.content.pm.PackageManager.NameNotFoundException;
    method public android.content.pm.LauncherApps.PinItemRequest getPinItemRequest(android.content.Intent);
@@ -11240,13 +11241,16 @@ package android.content.pm {
    method public void pinShortcuts(@NonNull String, @NonNull java.util.List<java.lang.String>, @NonNull android.os.UserHandle);
    method public void registerCallback(android.content.pm.LauncherApps.Callback);
    method public void registerCallback(android.content.pm.LauncherApps.Callback, android.os.Handler);
    method public void registerPackageInstallerSessionCallback(@NonNull java.util.concurrent.Executor, @NonNull android.content.pm.PackageInstaller.SessionCallback);
    method public android.content.pm.LauncherActivityInfo resolveActivity(android.content.Intent, android.os.UserHandle);
    method public boolean shouldHideFromSuggestions(@NonNull String, @NonNull android.os.UserHandle);
    method public void startAppDetailsActivity(android.content.ComponentName, android.os.UserHandle, android.graphics.Rect, android.os.Bundle);
    method public void startMainActivity(android.content.ComponentName, android.os.UserHandle, android.graphics.Rect, android.os.Bundle);
    method public void startPackageInstallerSessionDetailsActivity(android.content.pm.PackageInstaller.SessionInfo, android.graphics.Rect, android.os.Bundle);
    method public void startShortcut(@NonNull String, @NonNull String, @Nullable android.graphics.Rect, @Nullable android.os.Bundle, @NonNull android.os.UserHandle);
    method public void startShortcut(@NonNull android.content.pm.ShortcutInfo, @Nullable android.graphics.Rect, @Nullable android.os.Bundle);
    method public void unregisterCallback(android.content.pm.LauncherApps.Callback);
    method public void unregisterPackageInstallerSessionCallback(android.content.pm.PackageInstaller.SessionCallback);
    field public static final String ACTION_CONFIRM_PIN_APPWIDGET = "android.content.pm.action.CONFIRM_PIN_APPWIDGET";
    field public static final String ACTION_CONFIRM_PIN_SHORTCUT = "android.content.pm.action.CONFIRM_PIN_SHORTCUT";
    field public static final String EXTRA_PIN_ITEM_REQUEST = "android.content.pm.extra.PIN_ITEM_REQUEST";
@@ -11436,6 +11440,7 @@ package android.content.pm {
    method public long getSize();
    method public int getStagedSessionErrorCode();
    method public String getStagedSessionErrorMessage();
    method public android.os.UserHandle getUser();
    method public boolean isActive();
    method public boolean isMultiPackage();
    method public boolean isSealed();
+10 −0
Original line number Diff line number Diff line
@@ -24,6 +24,8 @@ import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.IOnAppsChangedListener;
import android.content.pm.LauncherApps;
import android.content.pm.IPackageInstallerCallback;
import android.content.pm.PackageInstaller;
import android.content.pm.ParceledListSlice;
import android.content.pm.ResolveInfo;
import android.content.pm.ShortcutInfo;
@@ -44,6 +46,9 @@ interface ILauncherApps {
            String callingPackage, String packageName, in UserHandle user);
    ActivityInfo resolveActivity(
            String callingPackage, in ComponentName component, in UserHandle user);
    void startSessionDetailsActivityAsUser(in IApplicationThread caller, String callingPackage,
                in PackageInstaller.SessionInfo sessionInfo, in Rect sourceBounds, in Bundle opts,
                in UserHandle user);
    void startActivityAsUser(in IApplicationThread caller, String callingPackage,
            in ComponentName component, in Rect sourceBounds,
            in Bundle opts, in UserHandle user);
@@ -79,4 +84,9 @@ interface ILauncherApps {
            String callingPackage, String packageName, in UserHandle user);
    IntentSender getShortcutConfigActivityIntent(String callingPackage, in ComponentName component,
            in UserHandle user);

    // Unregister is performed using package installer
    void registerPackageInstallerCallback(String callingPackage,
            in IPackageInstallerCallback callback);
    ParceledListSlice getAllSessions(String callingPackage);
}
+86 −4
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package android.content.pm;

import android.annotation.CallbackExecutor;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -32,6 +33,9 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentSender;
import android.content.pm.PackageInstaller.SessionCallback;
import android.content.pm.PackageInstaller.SessionCallbackDelegate;
import android.content.pm.PackageInstaller.SessionInfo;
import android.content.pm.PackageManager.ApplicationInfoFlags;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Resources;
@@ -65,7 +69,9 @@ import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.Executor;

/**
 * Class for retrieving a list of launchable activities for the current user and any associated
@@ -154,8 +160,8 @@ public class LauncherApps {
    private final PackageManager mPm;
    private final UserManager mUserManager;

    private List<CallbackMessageHandler> mCallbacks
            = new ArrayList<CallbackMessageHandler>();
    private final List<CallbackMessageHandler> mCallbacks = new ArrayList<>();
    private final List<SessionCallbackDelegate> mDelegates = new ArrayList<>();

    /**
     * Callbacks for package changes to this and related managed profiles.
@@ -571,6 +577,24 @@ public class LauncherApps {
        }
    }

    /**
     * Starts an activity to show the details of the specified session.
     *
     * @param sessionInfo The SessionInfo of the session
     * @param sourceBounds The Rect containing the source bounds of the clicked icon
     * @param opts Options to pass to startActivity
     */
    public void startPackageInstallerSessionDetailsActivity(SessionInfo sessionInfo,
            Rect sourceBounds, Bundle opts) {
        try {
            mService.startSessionDetailsActivityAsUser(mContext.getIApplicationThread(),
                    mContext.getPackageName(), sessionInfo, sourceBounds, opts,
                    sessionInfo.getUser());
        } catch (RemoteException re) {
            throw re.rethrowFromSystemServer();
        }
    }

    /**
     * Starts the settings activity to show the application details for a
     * package in the specified profile.
@@ -1128,7 +1152,7 @@ public class LauncherApps {
    }

    /**
     * Registers a callback for changes to packages in current and managed profiles.
     * Registers a callback for changes to packages in this user and managed profiles.
     *
     * @param callback The callback to register.
     */
@@ -1137,7 +1161,7 @@ public class LauncherApps {
    }

    /**
     * Registers a callback for changes to packages in current and managed profiles.
     * Registers a callback for changes to packages in this user and managed profiles.
     *
     * @param callback The callback to register.
     * @param handler that should be used to post callbacks on, may be null.
@@ -1442,6 +1466,64 @@ public class LauncherApps {
        }
    }

    /**
     * Register a callback to watch for session lifecycle events in this user and managed profiles.
     * @param callback The callback to register.
     * @param executor {@link Executor} to handle the callbacks, cannot be null.
     *
     * @see PackageInstaller#registerSessionCallback(SessionCallback)
     */
    public void registerPackageInstallerSessionCallback(
            @NonNull @CallbackExecutor Executor executor, @NonNull SessionCallback callback) {
        if (executor == null) {
            throw new NullPointerException("Executor must not be null");
        }

        synchronized (mDelegates) {
            final SessionCallbackDelegate delegate = new SessionCallbackDelegate(callback,
                    executor);
            try {
                mService.registerPackageInstallerCallback(mContext.getPackageName(),
                        delegate);
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
            mDelegates.add(delegate);
        }
    }

    /**
     * Unregisters a callback that was previously registered.
     *
     * @param callback The callback to unregister.
     * @see #registerPackageInstallerSessionCallback(Executor, SessionCallback)
     */
    public void unregisterPackageInstallerSessionCallback(SessionCallback callback) {
        synchronized (mDelegates) {
            for (Iterator<SessionCallbackDelegate> i = mDelegates.iterator(); i.hasNext();) {
                final SessionCallbackDelegate delegate = i.next();
                if (delegate.mCallback == callback) {
                    mPm.getPackageInstaller().unregisterSessionCallback(delegate.mCallback);
                    i.remove();
                }
            }
        }
    }

    /**
     * Return list of all known install sessions in this user and managed profiles, regardless
     * of the installer.
     *
     * @see PackageInstaller#getAllSessions()
     */
    public @NonNull List<SessionInfo> getAllPackageInstallerSessions() {
        try {
            return mService.getAllSessions(mContext.getPackageName()).getList();
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
     * A helper method to extract a {@link PinItemRequest} set to
     * the {@link #EXTRA_PIN_ITEM_REQUEST} extra.
+30 −40
Original line number Diff line number Diff line
@@ -36,20 +36,21 @@ import android.net.Uri;
import android.os.Build;
import android.os.FileBridge;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.HandlerExecutor;
import android.os.Parcel;
import android.os.ParcelFileDescriptor;
import android.os.Parcelable;
import android.os.ParcelableException;
import android.os.RemoteException;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.system.ErrnoException;
import android.system.Os;
import android.util.ExceptionUtils;

import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Preconditions;
import com.android.internal.util.function.pooled.PooledLambda;

import java.io.Closeable;
import java.io.IOException;
@@ -61,6 +62,7 @@ import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.Executor;

/**
 * Offers the ability to install, upgrade, and remove applications on the
@@ -659,8 +661,7 @@ public class PackageInstaller {
    }

    /** {@hide} */
    private static class SessionCallbackDelegate extends IPackageInstallerCallback.Stub implements
            Handler.Callback {
    static class SessionCallbackDelegate extends IPackageInstallerCallback.Stub {
        private static final int MSG_SESSION_CREATED = 1;
        private static final int MSG_SESSION_BADGING_CHANGED = 2;
        private static final int MSG_SESSION_ACTIVE_CHANGED = 3;
@@ -668,63 +669,41 @@ public class PackageInstaller {
        private static final int MSG_SESSION_FINISHED = 5;

        final SessionCallback mCallback;
        final Handler mHandler;
        final Executor mExecutor;

        public SessionCallbackDelegate(SessionCallback callback, Looper looper) {
        SessionCallbackDelegate(SessionCallback callback, Executor executor) {
            mCallback = callback;
            mHandler = new Handler(looper, this);
        }

        @Override
        public boolean handleMessage(Message msg) {
            final int sessionId = msg.arg1;
            switch (msg.what) {
                case MSG_SESSION_CREATED:
                    mCallback.onCreated(sessionId);
                    return true;
                case MSG_SESSION_BADGING_CHANGED:
                    mCallback.onBadgingChanged(sessionId);
                    return true;
                case MSG_SESSION_ACTIVE_CHANGED:
                    final boolean active = msg.arg2 != 0;
                    mCallback.onActiveChanged(sessionId, active);
                    return true;
                case MSG_SESSION_PROGRESS_CHANGED:
                    mCallback.onProgressChanged(sessionId, (float) msg.obj);
                    return true;
                case MSG_SESSION_FINISHED:
                    mCallback.onFinished(sessionId, msg.arg2 != 0);
                    return true;
            }
            return false;
            mExecutor = executor;
        }

        @Override
        public void onSessionCreated(int sessionId) {
            mHandler.obtainMessage(MSG_SESSION_CREATED, sessionId, 0).sendToTarget();
            mExecutor.execute(PooledLambda.obtainRunnable(SessionCallback::onCreated, mCallback,
                    sessionId).recycleOnUse());
        }

        @Override
        public void onSessionBadgingChanged(int sessionId) {
            mHandler.obtainMessage(MSG_SESSION_BADGING_CHANGED, sessionId, 0).sendToTarget();
            mExecutor.execute(PooledLambda.obtainRunnable(SessionCallback::onBadgingChanged,
                    mCallback, sessionId).recycleOnUse());
        }

        @Override
        public void onSessionActiveChanged(int sessionId, boolean active) {
            mHandler.obtainMessage(MSG_SESSION_ACTIVE_CHANGED, sessionId, active ? 1 : 0)
                    .sendToTarget();
            mExecutor.execute(PooledLambda.obtainRunnable(SessionCallback::onActiveChanged,
                    mCallback, sessionId, active).recycleOnUse());
        }

        @Override
        public void onSessionProgressChanged(int sessionId, float progress) {
            mHandler.obtainMessage(MSG_SESSION_PROGRESS_CHANGED, sessionId, 0, progress)
                    .sendToTarget();
            mExecutor.execute(PooledLambda.obtainRunnable(SessionCallback::onProgressChanged,
                    mCallback, sessionId, progress).recycleOnUse());
        }

        @Override
        public void onSessionFinished(int sessionId, boolean success) {
            mHandler.obtainMessage(MSG_SESSION_FINISHED, sessionId, success ? 1 : 0)
                    .sendToTarget();
            mExecutor.execute(PooledLambda.obtainRunnable(SessionCallback::onFinished,
                    mCallback, sessionId, success).recycleOnUse());
        }
    }

@@ -758,7 +737,7 @@ public class PackageInstaller {
    public void registerSessionCallback(@NonNull SessionCallback callback, @NonNull Handler handler) {
        synchronized (mDelegates) {
            final SessionCallbackDelegate delegate = new SessionCallbackDelegate(callback,
                    handler.getLooper());
                    new HandlerExecutor(handler));
            try {
                mInstaller.registerCallback(delegate, mUserId);
            } catch (RemoteException e) {
@@ -1649,6 +1628,8 @@ public class PackageInstaller {
        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
        public int sessionId;
        /** {@hide} */
        public int userId;
        /** {@hide} */
        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
        public String installerPackageName;
        /** {@hide} */
@@ -1720,6 +1701,7 @@ public class PackageInstaller {
        /** {@hide} */
        public SessionInfo(Parcel source) {
            sessionId = source.readInt();
            userId = source.readInt();
            installerPackageName = source.readString();
            resolvedBaseCodePath = source.readString();
            progress = source.readFloat();
@@ -1760,6 +1742,13 @@ public class PackageInstaller {
            return sessionId;
        }

        /**
         * Return the user associated with this session.
         */
        public UserHandle getUser() {
            return new UserHandle(userId);
        }

        /**
         * Return the package name of the app that owns this session.
         */
@@ -2091,6 +2080,7 @@ public class PackageInstaller {
        @Override
        public void writeToParcel(Parcel dest, int flags) {
            dest.writeInt(sessionId);
            dest.writeInt(userId);
            dest.writeString(installerPackageName);
            dest.writeString(resolvedBaseCodePath);
            dest.writeFloat(progress);
+68 −4
Original line number Diff line number Diff line
@@ -34,9 +34,11 @@ import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.ILauncherApps;
import android.content.pm.IOnAppsChangedListener;
import android.content.pm.IPackageInstallerCallback;
import android.content.pm.LauncherApps;
import android.content.pm.LauncherApps.ShortcutQuery;
import android.content.pm.PackageInfo;
import android.content.pm.PackageInstaller.SessionInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.content.pm.ParceledListSlice;
@@ -56,6 +58,7 @@ import android.os.IInterface;
import android.os.ParcelFileDescriptor;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.UserManagerInternal;
@@ -153,6 +156,8 @@ public class LauncherAppsService extends SystemService {

        private final Object mVouchedSignaturesLocked = new Object();

        private PackageInstallerService mPackageInstallerService;

        public LauncherAppsImpl(Context context) {
            mContext = context;
            mUm = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
@@ -204,8 +209,7 @@ public class LauncherAppsService extends SystemService {
        }

        /*
         * @see android.content.pm.ILauncherApps#addOnAppsChangedListener(
         *          android.content.pm.IOnAppsChangedListener)
         * @see android.content.pm.ILauncherApps#addOnAppsChangedListener
         */
        @Override
        public void addOnAppsChangedListener(String callingPackage, IOnAppsChangedListener listener)
@@ -228,8 +232,7 @@ public class LauncherAppsService extends SystemService {
        }

        /*
         * @see android.content.pm.ILauncherApps#removeOnAppsChangedListener(
         *          android.content.pm.IOnAppsChangedListener)
         * @see android.content.pm.ILauncherApps#removeOnAppsChangedListener
         */
        @Override
        public void removeOnAppsChangedListener(IOnAppsChangedListener listener)
@@ -245,6 +248,44 @@ public class LauncherAppsService extends SystemService {
            }
        }

        /**
         * @see android.content.pm.ILauncherApps#registerPackageInstallerCallback
         */
        @Override
        public void registerPackageInstallerCallback(String callingPackage,
                IPackageInstallerCallback callback) {
            verifyCallingPackage(callingPackage);
            UserHandle callingIdUserHandle = new UserHandle(getCallingUserId());
            getPackageInstallerService().registerCallback(callback, eventUserId ->
                            isEnabledProfileOf(callingIdUserHandle,
                                    new UserHandle(eventUserId), "shouldReceiveEvent"));
        }

        @Override
        public ParceledListSlice<SessionInfo> getAllSessions(String callingPackage) {
            verifyCallingPackage(callingPackage);
            List<SessionInfo> sessionInfos = new ArrayList<>();
            int[] userIds = mUm.getEnabledProfileIds(getCallingUserId());
            long token = Binder.clearCallingIdentity();
            try {
                for (int userId : userIds) {
                    sessionInfos.addAll(getPackageInstallerService().getAllSessions(userId)
                            .getList());
                }
            } finally {
                Binder.restoreCallingIdentity(token);
            }
            return new ParceledListSlice<>(sessionInfos);
        }

        private PackageInstallerService getPackageInstallerService() {
            if (mPackageInstallerService == null) {
                mPackageInstallerService = ((PackageInstallerService) ((PackageManagerService)
                        ServiceManager.getService("package")).getPackageInstaller());
            }
            return mPackageInstallerService;
        }

        /**
         * Register a receiver to watch for package broadcasts
         */
@@ -843,6 +884,29 @@ public class LauncherAppsService extends SystemService {
            }
        }

        @Override
        public void startSessionDetailsActivityAsUser(IApplicationThread caller,
                String callingPackage, SessionInfo sessionInfo, Rect sourceBounds,
                Bundle opts, UserHandle userHandle) throws RemoteException {
            int userId = userHandle.getIdentifier();
            if (!canAccessProfile(userId, "Cannot start details activity")) {
                return;
            }

            Intent i = new Intent(Intent.ACTION_VIEW)
                    .setData(new Uri.Builder()
                            .scheme("market")
                            .authority("details")
                            .appendQueryParameter("id", sessionInfo.appPackageName)
                            .build())
                    .putExtra(Intent.EXTRA_REFERRER, new Uri.Builder().scheme("android-app")
                            .authority(callingPackage).build());
            i.setSourceBounds(sourceBounds);

            mActivityTaskManagerInternal.startActivityAsUser(caller, callingPackage, i, opts,
                    userId);
        }

        @Override
        public void startActivityAsUser(IApplicationThread caller, String callingPackage,
                ComponentName component, Rect sourceBounds,
Loading