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

Commit 1ba7f836 authored by Automerger Merge Worker's avatar Automerger Merge Worker
Browse files

Merge "Merge "Handle race conditions in SCS when statsd dies" into rvc-dev am:...

Merge "Merge "Handle race conditions in SCS when statsd dies" into rvc-dev am: 76994e73 am: 235b5837" into rvc-d1-dev-plus-aosp am: 994315aa

Change-Id: I14b5f773aa3b8dfe3359d00469069cc8f49e9089
parents 2fd80811 994315aa
Loading
Loading
Loading
Loading
+73 −86
Original line number Diff line number Diff line
@@ -54,11 +54,11 @@ import java.io.FileDescriptor;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * Helper service for statsd (the native stats management service in cmds/statsd/).
@@ -112,17 +112,8 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
    private final HashMap<Long, String> mDeletedFiles = new HashMap<>();
    private final CompanionHandler mHandler;

    // Flag that is set when PHASE_BOOT_COMPLETED is triggered in the StatsCompanion lifecycle. This
    // and the flag mSentBootComplete below is used for synchronization to ensure that the boot
    // complete signal is only ever sent once to statsd. Two signals are needed because
    // #sayHiToStatsd can be called from both statsd and #onBootPhase
    // PHASE_THIRD_PARTY_APPS_CAN_START.
    @GuardedBy("sStatsdLock")
    private boolean mBootCompleted = false;
    // Flag that is set when IStatsd#bootCompleted is called. This flag ensures that boot complete
    // signal is only ever sent once.
    @GuardedBy("sStatsdLock")
    private boolean mSentBootComplete = false;
    // Flag that is set when PHASE_BOOT_COMPLETED is triggered in the StatsCompanion lifecycle.
    private AtomicBoolean mBootCompleted = new AtomicBoolean(false);

    public StatsCompanionService(Context context) {
        super();
@@ -607,27 +598,35 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
    // Statsd related code

    /**
     * Fetches the statsd IBinder service. This is a blocking call.
     * Fetches the statsd IBinder service. This is a blocking call that always refetches statsd
     * instead of returning the cached sStatsd.
     * Note: This should only be called from {@link #sayHiToStatsd()}. All other clients should use
     * the cached sStatsd via {@link #getStatsdNonblocking()}.
     */
    private IStatsd fetchStatsdService(StatsdDeathRecipient deathRecipient) {
        synchronized (sStatsdLock) {
            if (sStatsd == null) {
    private IStatsd fetchStatsdServiceLocked() {
        sStatsd = IStatsd.Stub.asInterface(StatsFrameworkInitializer
                .getStatsServiceManager()
                .getStatsdServiceRegisterer()
                .get());
                if (sStatsd != null) {
        return sStatsd;
    }

    private void registerStatsdDeathRecipient(IStatsd statsd, List<BroadcastReceiver> receivers) {
        StatsdDeathRecipient deathRecipient = new StatsdDeathRecipient(statsd, receivers);

        try {
                        sStatsd.asBinder().linkToDeath(deathRecipient, /* flags */ 0);
            statsd.asBinder().linkToDeath(deathRecipient, /*flags=*/0);
        } catch (RemoteException e) {
            Log.e(TAG, "linkToDeath (StatsdDeathRecipient) failed");
                        statsdNotReadyLocked();
            // Statsd has already died. Unregister receivers ourselves.
            for (BroadcastReceiver receiver : receivers) {
                mContext.unregisterReceiver(receiver);
            }
            synchronized (sStatsdLock) {
                if (statsd == sStatsd) {
                    statsdNotReadyLocked();
                }
            }
            return sStatsd;
        }
    }

@@ -648,22 +647,23 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
     * statsd.
     */
    private void sayHiToStatsd() {
        if (getStatsdNonblocking() != null) {
            Log.e(TAG, "Trying to fetch statsd, but it was already fetched",
                    new IllegalStateException(
                            "sStatsd is not null when being fetched"));
        IStatsd statsd;
        synchronized (sStatsdLock) {
            if (sStatsd != null && sStatsd.asBinder().isBinderAlive()) {
                Log.e(TAG, "statsd has already been fetched before",
                        new IllegalStateException("IStatsd object should be null or dead"));
                return;
            }
        StatsdDeathRecipient deathRecipient = new StatsdDeathRecipient();
        IStatsd statsd = fetchStatsdService(deathRecipient);
            statsd = fetchStatsdServiceLocked();
        }

        if (statsd == null) {
            Log.i(TAG,
                    "Could not yet find statsd to tell it that StatsCompanion is "
                            + "alive.");
            Log.i(TAG, "Could not yet find statsd to tell it that StatsCompanion is alive.");
            return;
        }
        mStatsManagerService.statsdReady(statsd);

        if (DEBUG) Log.d(TAG, "Saying hi to statsd");
        mStatsManagerService.statsdReady(statsd);
        try {
            statsd.statsCompanionReady();

@@ -682,8 +682,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
            mContext.registerReceiverForAllUsers(appUpdateReceiver, filter, null, null);

            // Setup receiver for user initialize (which happens once for a new user)
            // and
            // if a user is removed.
            // and if a user is removed.
            filter = new IntentFilter(Intent.ACTION_USER_INITIALIZE);
            filter.addAction(Intent.ACTION_USER_REMOVED);
            mContext.registerReceiverForAllUsers(userUpdateReceiver, filter, null, null);
@@ -691,27 +690,20 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
            // Setup receiver for device reboots or shutdowns.
            filter = new IntentFilter(Intent.ACTION_REBOOT);
            filter.addAction(Intent.ACTION_SHUTDOWN);
            mContext.registerReceiverForAllUsers(
                    shutdownEventReceiver, filter, null, null);
            mContext.registerReceiverForAllUsers(shutdownEventReceiver, filter, null, null);

            // Only add the receivers if the registration is successful.
            deathRecipient.addRegisteredBroadcastReceivers(
                    List.of(appUpdateReceiver, userUpdateReceiver, shutdownEventReceiver));
            // Register death recipient.
            List<BroadcastReceiver> broadcastReceivers =
                    List.of(appUpdateReceiver, userUpdateReceiver, shutdownEventReceiver);
            registerStatsdDeathRecipient(statsd, broadcastReceivers);

            // Used so we can call statsd.bootComplete() outside of the lock.
            boolean shouldSendBootComplete = false;
            synchronized (sStatsdLock) {
                if (mBootCompleted && !mSentBootComplete) {
                    mSentBootComplete = true;
                    shouldSendBootComplete = true;
                }
            }
            if (shouldSendBootComplete) {
            // Tell statsd that boot has completed. The signal may have already been sent, but since
            // the signal-receiving function is idempotent, that's ok.
            if (mBootCompleted.get()) {
                statsd.bootCompleted();
            }

            // Pull the latest state of UID->app name, version mapping when
            // statsd starts.
            // Pull the latest state of UID->app name, version mapping when statsd starts.
            informAllUids(mContext);

            Log.i(TAG, "Told statsd that StatsCompanionService is alive.");
@@ -722,18 +714,16 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {

    private class StatsdDeathRecipient implements IBinder.DeathRecipient {

        private List<BroadcastReceiver> mReceiversToUnregister;

        StatsdDeathRecipient() {
            mReceiversToUnregister = new ArrayList<>();
        }
        private final IStatsd mStatsd;
        private final List<BroadcastReceiver> mReceiversToUnregister;

        public void addRegisteredBroadcastReceivers(List<BroadcastReceiver> receivers) {
            synchronized (sStatsdLock) {
                mReceiversToUnregister.addAll(receivers);
            }
        StatsdDeathRecipient(IStatsd statsd, List<BroadcastReceiver> receivers) {
            mStatsd = statsd;
            mReceiversToUnregister = receivers;
        }

        // It is possible for binderDied to be called after a restarted statsd calls statsdReady,
        // but that's alright because the code does not assume an ordering of the two calls.
        @Override
        public void binderDied() {
            Log.i(TAG, "Statsd is dead - erase all my knowledge, except pullers");
@@ -762,13 +752,19 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
                        }
                    }
                }
                // We only unregister in binder death becaseu receivers can only be unregistered
                // once, or an IllegalArgumentException is thrown.

                // Unregister receivers on death because receivers can only be unregistered once.
                // Otherwise, an IllegalArgumentException is thrown.
                for (BroadcastReceiver receiver: mReceiversToUnregister) {
                    mContext.unregisterReceiver(receiver);
                }

                // It's possible for statsd to have restarted and called statsdReady, causing a new
                // sStatsd binder object to be fetched, before the binderDied callback runs. Only
                // call #statsdNotReadyLocked if that hasn't happened yet.
                if (mStatsd == sStatsd) {
                    statsdNotReadyLocked();
                mSentBootComplete = false;
                }
            }
        }
    }
@@ -779,20 +775,13 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
    }

    void bootCompleted() {
        mBootCompleted.set(true);
        IStatsd statsd = getStatsdNonblocking();
        synchronized (sStatsdLock) {
            mBootCompleted = true;
            if (mSentBootComplete) {
                // do not send a boot complete a second time.
                return;
            }
        if (statsd == null) {
            // Statsd is not yet ready.
            // Delay the boot completed ping to {@link #sayHiToStatsd()}
            return;
        }
            mSentBootComplete = true;
        }
        try {
            statsd.bootCompleted();
        } catch (RemoteException e) {
@@ -808,8 +797,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
        }

        synchronized (sStatsdLock) {
            writer.println(
                    "Number of configuration files deleted: " + mDeletedFiles.size());
            writer.println("Number of configuration files deleted: " + mDeletedFiles.size());
            if (mDeletedFiles.size() > 0) {
                writer.println("  timestamp, deleted file name");
            }
@@ -817,8 +805,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
                    SystemClock.currentThreadTimeMillis() - SystemClock.elapsedRealtime();
            for (Long elapsedMillis : mDeletedFiles.keySet()) {
                long deletionMillis = lastBootMillis + elapsedMillis;
                writer.println(
                        "  " + deletionMillis + ", " + mDeletedFiles.get(elapsedMillis));
                writer.println("  " + deletionMillis + ", " + mDeletedFiles.get(elapsedMillis));
            }
        }
    }
+2 −0
Original line number Diff line number Diff line
@@ -343,9 +343,11 @@ status_t StatsService::handleShellCommand(int in, int out, int err, const char**
        if (!utf8Args[0].compare(String8("print-logs"))) {
            return cmd_print_logs(out, utf8Args);
        }

        if (!utf8Args[0].compare(String8("send-active-configs"))) {
            return cmd_trigger_active_config_broadcast(out, utf8Args);
        }

        if (!utf8Args[0].compare(String8("data-subscribe"))) {
            {
                std::lock_guard<std::mutex> lock(mShellSubscriberMutex);