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

Commit 3680ae62 authored by Marcin Oczeretko's avatar Marcin Oczeretko
Browse files

Add a flag to enable/disable LooperStats collection

Test: Manually tested

Change-Id: I9cd4c819297ea34ab59c3cf9cfd11136987acc22
parent ec3471c1
Loading
Loading
Loading
Loading
+13 −0
Original line number Diff line number Diff line
@@ -13319,6 +13319,19 @@ public final class Settings {
         */
        public static final String BINDER_CALLS_STATS = "binder_calls_stats";
        /**
         * Looper stats settings.
         *
         * The following strings are supported as keys:
         * <pre>
         *     enabled              (boolean)
         *     sampling_interval    (int)
         * </pre>
         *
         * @hide
         */
        public static final String LOOPER_STATS = "looper_stats";
        /**
         * Default user id to boot into. They map to user ids, for example, 10, 11, 12.
         *
+5 −7
Original line number Diff line number Diff line
@@ -37,8 +37,6 @@ import java.util.concurrent.ThreadLocalRandom;
 */
public class LooperStats implements Looper.Observer {
    private static final int TOKEN_POOL_SIZE = 50;
    private static final int DEFAULT_ENTRIES_SIZE_CAP = 2000;
    private static final int DEFAULT_SAMPLING_INTERVAL = 100;

    @GuardedBy("mLock")
    private final SparseArray<Entry> mEntries = new SparseArray<>(256);
@@ -47,12 +45,8 @@ public class LooperStats implements Looper.Observer {
    private final Entry mHashCollisionEntry = new Entry("HASH_COLLISION");
    private final ConcurrentLinkedQueue<DispatchSession> mSessionPool =
            new ConcurrentLinkedQueue<>();
    private final int mSamplingInterval;
    private final int mEntriesSizeCap;

    public LooperStats() {
        this(DEFAULT_SAMPLING_INTERVAL, DEFAULT_ENTRIES_SIZE_CAP);
    }
    private int mSamplingInterval;

    public LooperStats(int samplingInterval, int entriesSizeCap) {
        this.mSamplingInterval = samplingInterval;
@@ -142,6 +136,10 @@ public class LooperStats implements Looper.Observer {
        }
    }

    public void setSamplingInterval(int samplingInterval) {
        mSamplingInterval = samplingInterval;
    }

    @NonNull
    private Entry getOrCreateEntry(Message msg) {
        final int id = Entry.idFor(msg);
+1 −0
Original line number Diff line number Diff line
@@ -282,6 +282,7 @@ public class SettingsBackupTest {
                    Settings.Global.LOCATION_GLOBAL_KILL_SWITCH,
                    Settings.Global.LOCATION_SETTINGS_LINK_TO_PERMISSIONS_ENABLED,
                    Settings.Global.LOCK_SOUND,
                    Settings.Global.LOOPER_STATS,
                    Settings.Global.LOW_BATTERY_SOUND,
                    Settings.Global.LOW_BATTERY_SOUND_TIMEOUT,
                    Settings.Global.LOW_POWER_MODE,
+69 −2
Original line number Diff line number Diff line
@@ -17,12 +17,20 @@
package com.android.server;

import android.content.Context;
import android.database.ContentObserver;
import android.net.Uri;
import android.os.Binder;
import android.os.Looper;
import android.os.ResultReceiver;
import android.os.ShellCallback;
import android.os.ShellCommand;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.provider.Settings;
import android.util.KeyValueListParser;
import android.util.Slog;

import com.android.internal.os.BackgroundThread;
import com.android.internal.os.LooperStats;
import com.android.internal.util.DumpUtils;

@@ -38,6 +46,13 @@ import java.util.List;
public class LooperStatsService extends Binder {
    private static final String TAG = "LooperStatsService";
    private static final String LOOPER_STATS_SERVICE_NAME = "looper_stats";
    private static final String SETTINGS_ENABLED_KEY = "enabled";
    private static final String SETTINGS_SAMPLING_INTERVAL_KEY = "sampling_interval";
    private static final String DEBUG_SYS_LOOPER_STATS_ENABLED =
            "debug.sys.looper_stats_enabled";
    private static final int DEFAULT_SAMPLING_INTERVAL = 100;
    private static final int DEFAULT_ENTRIES_SIZE_CAP = 2000;
    private static final boolean DEFAULT_ENABLED = false;

    private final Context mContext;
    private final LooperStats mStats;
@@ -48,6 +63,24 @@ public class LooperStatsService extends Binder {
        this.mStats = stats;
    }

    private void initFromSettings() {
        final KeyValueListParser parser = new KeyValueListParser(',');

        try {
            parser.setString(Settings.Global.getString(mContext.getContentResolver(),
                    Settings.Global.LOOPER_STATS));
        } catch (IllegalArgumentException e) {
            Slog.e(TAG, "Bad looper_stats settings", e);
        }

        setSamplingInterval(
                parser.getInt(SETTINGS_SAMPLING_INTERVAL_KEY, DEFAULT_SAMPLING_INTERVAL));
        // Manually specified value takes precedence over Settings.
        setEnabled(SystemProperties.getBoolean(
                DEBUG_SYS_LOOPER_STATS_ENABLED,
                parser.getBoolean(SETTINGS_ENABLED_KEY, DEFAULT_ENABLED)));
    }

    @Override
    public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
            String[] args, ShellCallback callback, ResultReceiver resultReceiver) {
@@ -90,20 +123,54 @@ public class LooperStatsService extends Binder {
        }
    }

    private void setSamplingInterval(int samplingInterval) {
        mStats.setSamplingInterval(samplingInterval);
    }

    /**
     * Manages the lifecycle of LooperStatsService within System Server.
     */
    public static class Lifecycle extends SystemService {
        private final SettingsObserver mSettingsObserver;
        private final LooperStatsService mService;
        private final LooperStats mStats;

        public Lifecycle(Context context) {
            super(context);
            mStats = new LooperStats(DEFAULT_SAMPLING_INTERVAL, DEFAULT_ENTRIES_SIZE_CAP);
            mService = new LooperStatsService(getContext(), mStats);
            mSettingsObserver = new SettingsObserver(mService);
        }

        @Override
        public void onStart() {
            LooperStats stats = new LooperStats();
            publishLocalService(LooperStats.class, stats);
            publishLocalService(LooperStats.class, mStats);
            // TODO: publish LooperStatsService as a binder service when the SE Policy is changed.
        }

        @Override
        public void onBootPhase(int phase) {
            if (SystemService.PHASE_SYSTEM_SERVICES_READY == phase) {
                mService.initFromSettings();
                Uri settingsUri = Settings.Global.getUriFor(Settings.Global.LOOPER_STATS);
                getContext().getContentResolver().registerContentObserver(
                        settingsUri, false, mSettingsObserver, UserHandle.USER_SYSTEM);
            }
        }
    }

    private static class SettingsObserver extends ContentObserver {
        private final LooperStatsService mService;

        SettingsObserver(LooperStatsService service) {
            super(BackgroundThread.getHandler());
            mService = service;
        }

        @Override
        public void onChange(boolean selfChange, Uri uri, int userId) {
            mService.initFromSettings();
        }
    }

    private class LooperShellCommand extends ShellCommand {