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

Commit 4f5e3078 authored by Jared Duke's avatar Jared Duke Committed by Android (Google) Code Review
Browse files

Revert "Avoid locks in various singleton HandlerThread types"

This reverts commit 198ebf4b.

Reason for revert: Breaks some Robolectric tests that have fragile
assumptions about internals and reflections. Will fix when relanding.

Bug: 411249866
Bug: 414673812
Change-Id: I8dc7161992a493c1ccf5952e7dadb8f9c5f539e5
parent 198ebf4b
Loading
Loading
Loading
Loading
+28 −34
Original line number Diff line number Diff line
@@ -32,13 +32,9 @@ import java.util.concurrent.Executor;
public final class BackgroundThread extends HandlerThread {
    private static final long SLOW_DISPATCH_THRESHOLD_MS = 10_000;
    private static final long SLOW_DELIVERY_THRESHOLD_MS = 30_000;

    // Note: These static fields are shadowed in Robolectric, and cannot be easily changed without
    // breaking downstream tests. This makes refactoring or optimization a bit messier than it could
    // be, e.g., using common lazy singleton abstractions or the holder init pattern.
    private static volatile BackgroundThread sInstance;
    private static volatile Handler sHandler;
    private static volatile HandlerExecutor sHandlerExecutor;
    private static BackgroundThread sInstance;
    private static Handler sHandler;
    private static HandlerExecutor sHandlerExecutor;

    private BackgroundThread() {
        super("android.bg", android.os.Process.THREAD_PRIORITY_BACKGROUND);
@@ -51,14 +47,9 @@ public final class BackgroundThread extends HandlerThread {
        }
    }

    private static void ensureThreadReady() {
        // As the executor is assigned and initialized last, we use it to signal full readiness.
        if (sHandlerExecutor != null) {
            return;
        }
        synchronized (BackgroundThread.class) {
            if (sHandlerExecutor == null) {
    private static void ensureThreadReadyLocked() {
        ensureThreadStartedLocked();
        if (sHandler == null) {
            // This will block until the looper is initialized on the background thread.
            final Looper looper = sInstance.getLooper();
            looper.setTraceTag(Trace.TRACE_TAG_SYSTEM_SERVER);
@@ -69,34 +60,37 @@ public final class BackgroundThread extends HandlerThread {
            sHandlerExecutor = new HandlerExecutor(sHandler);
        }
    }
    }

    /**
     * Starts the thread if needed, but doesn't block on thread initialization or readiness.
     */
    public static void startIfNeeded() {
        if (sInstance == null) {
        synchronized (BackgroundThread.class) {
            ensureThreadStartedLocked();
        }
    }
    }

    @NonNull
    public static BackgroundThread get() {
        ensureThreadReady();
        synchronized (BackgroundThread.class) {
            ensureThreadReadyLocked();
            return sInstance;
        }
    }

    @NonNull
    public static Handler getHandler() {
        ensureThreadReady();
        synchronized (BackgroundThread.class) {
            ensureThreadReadyLocked();
            return sHandler;
        }
    }

    @NonNull
    public static Executor getExecutor() {
        ensureThreadReady();
        synchronized (BackgroundThread.class) {
            ensureThreadReadyLocked();
            return sHandlerExecutor;
        }
    }
}
+28 −15
Original line number Diff line number Diff line
@@ -38,32 +38,45 @@ public final class FgThread extends ServiceThread {
    private static final long SLOW_DISPATCH_THRESHOLD_MS = 100;
    private static final long SLOW_DELIVERY_THRESHOLD_MS = 200;

    private static final class NoPreloadHolder {
        private static final FgThread sInstance = new FgThread();
    }

    private final Handler mHandler;
    private final HandlerExecutor mHandlerExecutor;
    private static FgThread sInstance;
    private static Handler sHandler;
    private static HandlerExecutor sHandlerExecutor;

    private FgThread() {
        super("android.fg", android.os.Process.THREAD_PRIORITY_DEFAULT, true /*allowIo*/);
        start();
        final Looper looper = getLooper();
    }

    private static void ensureThreadLocked() {
        if (sInstance == null) {
            sInstance = new FgThread();
            sInstance.start();
            final Looper looper = sInstance.getLooper();
            looper.setTraceTag(Trace.TRACE_TAG_SYSTEM_SERVER);
        looper.setSlowLogThresholdMs(SLOW_DISPATCH_THRESHOLD_MS, SLOW_DELIVERY_THRESHOLD_MS);
        mHandler = makeSharedHandler(looper);
        mHandlerExecutor = new HandlerExecutor(mHandler);
            looper.setSlowLogThresholdMs(
                    SLOW_DISPATCH_THRESHOLD_MS, SLOW_DELIVERY_THRESHOLD_MS);
            sHandler = makeSharedHandler(sInstance.getLooper());
            sHandlerExecutor = new HandlerExecutor(sHandler);
        }
    }

    public static FgThread get() {
        return NoPreloadHolder.sInstance;
        synchronized (FgThread.class) {
            ensureThreadLocked();
            return sInstance;
        }
    }

    public static Handler getHandler() {
        return NoPreloadHolder.sInstance.mHandler;
        synchronized (FgThread.class) {
            ensureThreadLocked();
            return sHandler;
        }
    }

    public static Executor getExecutor() {
        return NoPreloadHolder.sInstance.mHandlerExecutor;
        synchronized (FgThread.class) {
            ensureThreadLocked();
            return sHandlerExecutor;
        }
    }
}
+25 −15
Original line number Diff line number Diff line
@@ -18,7 +18,6 @@ package com.android.server;

import android.os.Handler;
import android.os.HandlerExecutor;
import android.os.Looper;
import android.os.Trace;

import java.util.concurrent.Executor;
@@ -29,31 +28,42 @@ import java.util.concurrent.Executor;
 * (not waiting for data itself, but communicating with network daemons).
 */
public final class IoThread extends ServiceThread {
    private static final class NoPreloadHolder {
        private static final IoThread sInstance = new IoThread();
    }

    private final Handler mHandler;
    private final HandlerExecutor mHandlerExecutor;
    private static IoThread sInstance;
    private static Handler sHandler;
    private static HandlerExecutor sHandlerExecutor;

    private IoThread() {
        super("android.io", android.os.Process.THREAD_PRIORITY_DEFAULT, true /*allowIo*/);
        start();
        final Looper looper = getLooper();
        looper.setTraceTag(Trace.TRACE_TAG_SYSTEM_SERVER);
        mHandler = new Handler(looper, /*callback=*/ null, /* async=*/ false, /* shared=*/ true);
        mHandlerExecutor = new HandlerExecutor(mHandler);
    }

    private static void ensureThreadLocked() {
        if (sInstance == null) {
            sInstance = new IoThread();
            sInstance.start();
            sInstance.getLooper().setTraceTag(Trace.TRACE_TAG_SYSTEM_SERVER);
            sHandler = makeSharedHandler(sInstance.getLooper());
            sHandlerExecutor = new HandlerExecutor(sHandler);
        }
    }

    public static IoThread get() {
        return NoPreloadHolder.sInstance;
        synchronized (IoThread.class) {
            ensureThreadLocked();
            return sInstance;
        }
    }

    public static Handler getHandler() {
        return NoPreloadHolder.sInstance.mHandler;
        synchronized (IoThread.class) {
            ensureThreadLocked();
            return sHandler;
        }
    }

    public static Executor getExecutor() {
        return NoPreloadHolder.sInstance.mHandlerExecutor;
        synchronized (IoThread.class) {
            ensureThreadLocked();
            return sHandlerExecutor;
        }
    }
}
+35 −13
Original line number Diff line number Diff line
@@ -21,6 +21,8 @@ import android.os.HandlerExecutor;
import android.os.Looper;
import android.os.Trace;

import com.android.internal.annotations.GuardedBy;

import java.util.concurrent.Executor;

/**
@@ -32,41 +34,61 @@ public final class PermissionThread extends ServiceThread {
    private static final long SLOW_DISPATCH_THRESHOLD_MS = 100;
    private static final long SLOW_DELIVERY_THRESHOLD_MS = 200;

    private static final class NoPreloadHolder {
        private static final PermissionThread sInstance = new PermissionThread();
    }
    private static final Object sLock = new Object();

    private final Handler mHandler;
    private final HandlerExecutor mHandlerExecutor;
    @GuardedBy("sLock")
    private static PermissionThread sInstance;
    private static Handler sHandler;
    private static HandlerExecutor sHandlerExecutor;

    private PermissionThread() {
        super("android.perm", android.os.Process.THREAD_PRIORITY_DEFAULT, /* allowIo= */ true);
        start();
        final Looper looper = getLooper();
    }

    @GuardedBy("sLock")
    private static void ensureThreadLocked() {
        if (sInstance != null) {
            return;
        }

        sInstance = new PermissionThread();
        sInstance.start();
        final Looper looper = sInstance.getLooper();
        looper.setTraceTag(Trace.TRACE_TAG_SYSTEM_SERVER);
        looper.setSlowLogThresholdMs(SLOW_DISPATCH_THRESHOLD_MS, SLOW_DELIVERY_THRESHOLD_MS);
        mHandler = new Handler(looper);
        mHandlerExecutor = new HandlerExecutor(mHandler);
        looper.setSlowLogThresholdMs(
                SLOW_DISPATCH_THRESHOLD_MS, SLOW_DELIVERY_THRESHOLD_MS);
        sHandler = new Handler(sInstance.getLooper());
        sHandlerExecutor = new HandlerExecutor(sHandler);
    }

    /**
     * Obtain a singleton instance of the PermissionThread.
     */
    public static PermissionThread get() {
        return NoPreloadHolder.sInstance;
        synchronized (sLock) {
            ensureThreadLocked();
            return sInstance;
        }
    }

    /**
     * Obtain a singleton instance of a handler executing in the PermissionThread.
     */
    public static Handler getHandler() {
        return NoPreloadHolder.sInstance.mHandler;
        synchronized (sLock) {
            ensureThreadLocked();
            return sHandler;
        }
    }


    /**
     * Obtain a singleton instance of an executor of the PermissionThread.
     */
    public static Executor getExecutor() {
        return NoPreloadHolder.sInstance.mHandlerExecutor;
        synchronized (sLock) {
            ensureThreadLocked();
            return sHandlerExecutor;
        }
    }
}