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

Commit c2601346 authored by JW Wang's avatar JW Wang
Browse files

Add a method to notify when is safe to send broadcasts

See
https://source.corp.google.com/android/frameworks/base/services/core/java/com/android/server/pm/PackageInstallerService.java;rcl=45f6b4ce664df69d4f7db33f6d413a2574973121;l=286-288

It is possible for broadcasts to be rejected by AMS with an exception
even if mOkToSendBroadcasts is true. This causes b/160106846 and crashes
the system server which then fails staged installs as well as
StagedInstallTest.

Lifecycle listens to boot phases and calls #onBroadcastReady to notify
that it is now safe to send broadcasts.

Bug: 160106846
Test: atest StagedInstallTest
Change-Id: I984167c592411a1685e9d9f714d1cb22f0bc9964
parent 11894cac
Loading
Loading
Loading
Loading
+33 −10
Original line number Diff line number Diff line
@@ -84,6 +84,8 @@ import com.android.internal.util.IndentingPrintWriter;
import com.android.server.IoThread;
import com.android.server.LocalServices;
import com.android.server.SystemConfig;
import com.android.server.SystemService;
import com.android.server.SystemServiceManager;
import com.android.server.pm.parsing.PackageParser2;
import com.android.server.pm.permission.PermissionManagerServiceInternal;

@@ -201,6 +203,27 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
        }
    };

    private static final class Lifecycle extends SystemService {
        private final PackageInstallerService mPackageInstallerService;

        Lifecycle(Context context, PackageInstallerService service) {
            super(context);
            mPackageInstallerService = service;
        }

        @Override
        public void onStart() {
            // no-op
        }

        @Override
        public void onBootPhase(int phase) {
            if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
                mPackageInstallerService.onBroadcastReady();
            }
        }
    }

    public PackageInstallerService(Context context, PackageManagerService pm,
            Supplier<PackageParser2> apexParserSupplier) {
        mContext = context;
@@ -222,6 +245,9 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements

        mApexManager = ApexManager.getInstance();
        mStagingManager = new StagingManager(this, context, apexParserSupplier);

        LocalServices.getService(SystemServiceManager.class).startService(
                new Lifecycle(context, this));
    }

    boolean okToSendBroadcasts()  {
@@ -259,6 +285,13 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
        }
    }

    private void onBroadcastReady() {
        // Broadcasts are not sent while we restore sessions on boot, since no processes would be
        // ready to listen to them. From now on, it is safe to send broadcasts which otherwise will
        // be rejected by ActivityManagerService if its systemReady() is not completed.
        mOkToSendBroadcasts = true;
    }

    void restoreAndApplyStagedSessionIfNeeded() {
        List<PackageInstallerSession> stagedSessionsToRestore = new ArrayList<>();
        synchronized (mSessions) {
@@ -281,16 +314,6 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
            }
            mStagingManager.restoreSession(session, isDeviceUpgrading);
        }
        // Broadcasts are not sent while we restore sessions on boot, since no processes would be
        // ready to listen to them. From now on, we greedily assume that broadcasts requests are
        // safe to send out. The worst that can happen is that a broadcast is attempted before
        // ActivityManagerService completes its own systemReady(), in which case it will be rejected
        // with an otherwise harmless exception.
        // A more appropriate way to do this would be to wait until the correct  boot phase is
        // reached, but since we are not a SystemService we can't override onBootPhase.
        // Waiting on the BOOT_COMPLETED broadcast can take several minutes, so that's not a viable
        // way either.
        mOkToSendBroadcasts = true;
    }

    @GuardedBy("mSessions")