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

Commit 5cf5578a authored by Christopher Tate's avatar Christopher Tate
Browse files

Make sure FIRST_LAUNCH is after PACKAGE_ADDED

If an app undergoes restore during install, it is considered 'started'
and the FIRST_LAUNCH broadcast needs to go out.  However, this must not
take place until after the restore operation has fully completed, in
order to avoid publishing the app's existence while it may still be in
an incoherent state.  We now make this broadcast part of POST_INSTALL
in the restore case.

Bundled apps are in the 'started' state regardless, so no FIRST_LAUNCH
broadcast is ever sent for them -- this CL does not change that
existing behavior even in the case of setup-time data restore of
factory-installed packages.

Bug 28173625

Change-Id: Ibcc3758576662dc447b75476173a0d008a9fe4da
parent 68d180bb
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -222,7 +222,7 @@ interface IPackageManager {
            in String installerPackageName,
            int userId);

    void finishPackageInstall(int token);
    void finishPackageInstall(int token, boolean didLaunch);

    void setInstallerPackageName(in String targetPackage, in String installerPackageName);

+15 −2
Original line number Diff line number Diff line
@@ -7706,6 +7706,11 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF
        // when we're finished.
        private int mPmToken;

        // When this is restore-during-install, we need to tell the package manager
        // whether we actually launched the app, because this affects notifications
        // around externally-visible state transitions.
        private boolean mDidLaunch;

        // Is this a whole-system restore, i.e. are we establishing a new ancestral
        // dataset to base future restore-at-install operations from?
        private boolean mIsSystemRestore;
@@ -7769,6 +7774,7 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF
            mTargetPackage = targetPackage;
            mIsSystemRestore = isFullSystemRestore;
            mFinished = false;
            mDidLaunch = false;

            if (targetPackage != null) {
                // Single package restore
@@ -8149,6 +8155,9 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF
                return;
            }

            // Whatever happens next, we've launched the target app now; remember that.
            mDidLaunch = true;

            // And then finally start the restore on this agent
            try {
                initiateOneRestore(mCurrentPackage, metaInfo.versionCode);
@@ -8430,6 +8439,10 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF
                    // Now we're really done with this one too
                    IoUtils.closeQuietly(mEnginePipes[0]);

                    // In all cases we want to remember whether we launched
                    // the target app as part of our work so far.
                    mDidLaunch = (mEngine.getAgent() != null);

                    // If we hit a transport-level error, we are done with everything;
                    // if we hit an agent error we just go back to running the queue.
                    if (status == BackupTransport.TRANSPORT_OK) {
@@ -8522,7 +8535,7 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF
            if (mPmToken > 0) {
                if (MORE_DEBUG) Slog.v(TAG, "finishing PM token " + mPmToken);
                try {
                    mPackageManagerBinder.finishPackageInstall(mPmToken);
                    mPackageManagerBinder.finishPackageInstall(mPmToken, mDidLaunch);
                } catch (RemoteException e) { /* can't happen */ }
            } else {
                // We were invoked via an active restore session, not by the Package
@@ -9682,7 +9695,7 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF
            // Manager to proceed with the post-install handling for this package.
            if (DEBUG) Slog.v(TAG, "Finishing install immediately");
            try {
                mPackageManagerBinder.finishPackageInstall(token);
                mPackageManagerBinder.finishPackageInstall(token, false);
            } catch (RemoteException e) { /* can't happen */ }
        }
    }
+64 −4
Original line number Diff line number Diff line
@@ -1574,6 +1574,7 @@ public class PackageManagerService extends IPackageManager.Stub {
                    if (DEBUG_INSTALL) Log.v(TAG, "Handling post-install for " + msg.arg1);
                    PostInstallData data = mRunningInstalls.get(msg.arg1);
                    final boolean didRestore = (msg.arg2 != 0);
                    mRunningInstalls.delete(msg.arg1);
                    if (data != null) {
@@ -1588,7 +1589,8 @@ public class PackageManagerService extends IPackageManager.Stub {
                        // Handle the parent package
                        handlePackagePostInstall(parentRes, grantPermissions, killApp,
                                grantedPermissions, args.observer);
                                grantedPermissions, didRestore, args.installerPackageName,
                                args.observer);
                        // Handle the child packages
                        final int childCount = (parentRes.addedChildPackages != null)
@@ -1596,7 +1598,8 @@ public class PackageManagerService extends IPackageManager.Stub {
                        for (int i = 0; i < childCount; i++) {
                            PackageInstalledInfo childRes = parentRes.addedChildPackages.valueAt(i);
                            handlePackagePostInstall(childRes, grantPermissions, killApp,
                                    grantedPermissions, args.observer);
                                    grantedPermissions, false, args.installerPackageName,
                                    args.observer);
                        }
                        // Log tracing if needed
@@ -1792,6 +1795,7 @@ public class PackageManagerService extends IPackageManager.Stub {
    private void handlePackagePostInstall(PackageInstalledInfo res, boolean grantPermissions,
            boolean killApp, String[] grantedPermissions,
            boolean launchedForRestore, String installerPackage,
            IPackageInstallObserver2 installObserver) {
        if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
            // Send the removed broadcasts
@@ -1876,6 +1880,14 @@ public class PackageManagerService extends IPackageManager.Stub {
                            null /*package*/, null /*extras*/, 0 /*flags*/,
                            packageName /*targetPackage*/,
                            null /*finishedReceiver*/, updateUsers);
                } else if (launchedForRestore && !isSystemApp(res.pkg)) {
                    // First-install and we did a restore, so we're responsible for the
                    // first-launch broadcast.
                    if (DEBUG_BACKUP) {
                        Slog.i(TAG, "Post-restore of " + packageName
                                + " sending FIRST_LAUNCH in " + Arrays.toString(firstUsers));
                    }
                    sendFirstLaunchBroadcast(packageName, installerPackage, firstUsers);
                }
                // Send broadcast package appeared if forward locked/external for all users
@@ -11723,7 +11735,7 @@ public class PackageManagerService extends IPackageManager.Stub {
    }
    @Override
    public void finishPackageInstall(int token) {
    public void finishPackageInstall(int token, boolean didLaunch) {
        enforceSystemOrRoot("Only the system is allowed to finish installs");
        if (DEBUG_INSTALL) {
@@ -11731,7 +11743,7 @@ public class PackageManagerService extends IPackageManager.Stub {
        }
        Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "restore", token);
        final Message msg = mHandler.obtainMessage(POST_INSTALL, token, 0);
        final Message msg = mHandler.obtainMessage(POST_INSTALL, token, didLaunch ? 1 : 0);
        mHandler.sendMessage(msg);
    }
@@ -12060,6 +12072,54 @@ public class PackageManagerService extends IPackageManager.Stub {
        });
    }
    /**
     * Callback from PackageSettings whenever an app is first transitioned out of the
     * 'stopped' state.  Normally we just issue the broadcast, but we can't do that if
     * the app was "launched" for a restoreAtInstall operation.  Therefore we check
     * here whether the app is the target of an ongoing install, and only send the
     * broadcast immediately if it is not in that state.  If it *is* undergoing a restore,
     * the first-launch broadcast will be sent implicitly on that basis in POST_INSTALL
     * handling.
     */
    void notifyFirstLaunch(final String pkgName, final String installerPackage, final int userId) {
        // Serialize this with the rest of the install-process message chain.  In the
        // restore-at-install case, this Runnable will necessarily run before the
        // POST_INSTALL message is processed, so the contents of mRunningInstalls
        // are coherent.  In the non-restore case, the app has already completed install
        // and been launched through some other means, so it is not in a problematic
        // state for observers to see the FIRST_LAUNCH signal.
        mHandler.post(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < mRunningInstalls.size(); i++) {
                    final PostInstallData data = mRunningInstalls.valueAt(i);
                    if (pkgName.equals(data.res.pkg.applicationInfo.packageName)) {
                        // right package; but is it for the right user?
                        for (int uIndex = 0; uIndex < data.res.newUsers.length; uIndex++) {
                            if (userId == data.res.newUsers[uIndex]) {
                                if (DEBUG_BACKUP) {
                                    Slog.i(TAG, "Package " + pkgName
                                            + " being restored so deferring FIRST_LAUNCH");
                                }
                                return;
                            }
                        }
                    }
                }
                // didn't find it, so not being restored
                if (DEBUG_BACKUP) {
                    Slog.i(TAG, "Package " + pkgName + " sending normal FIRST_LAUNCH");
                }
                sendFirstLaunchBroadcast(pkgName, installerPackage, new int[] {userId});
            }
        });
    }
    private void sendFirstLaunchBroadcast(String pkgName, String installerPkg, int[] userIds) {
        sendPackageBroadcast(Intent.ACTION_PACKAGE_FIRST_LAUNCH, pkgName, null, 0,
                installerPkg, null, userIds);
    }
    private abstract class HandlerParams {
        private static final int MAX_RETRIES = 4;
+2 −4
Original line number Diff line number Diff line
@@ -4118,7 +4118,7 @@ final class Settings {
        return pkg.getCurrentEnabledStateLPr(classNameStr, userId);
    }

    boolean setPackageStoppedStateLPw(PackageManagerService yucky, String packageName,
    boolean setPackageStoppedStateLPw(PackageManagerService pm, String packageName,
            boolean stopped, boolean allowedByPermission, int uid, int userId) {
        int appId = UserHandle.getAppId(uid);
        final PackageSetting pkgSetting = mPackages.get(packageName);
@@ -4143,9 +4143,7 @@ final class Settings {
            // pkgSetting.pkg.mSetStopped = stopped;
            if (pkgSetting.getNotLaunched(userId)) {
                if (pkgSetting.installerPackageName != null) {
                    yucky.sendPackageBroadcast(Intent.ACTION_PACKAGE_FIRST_LAUNCH,
                            pkgSetting.name, null, 0,
                            pkgSetting.installerPackageName, null, new int[] {userId});
                    pm.notifyFirstLaunch(pkgSetting.name, pkgSetting.installerPackageName, userId);
                }
                pkgSetting.setNotLaunched(false, userId);
            }