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

Commit 54217e5c authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Added SystemServerInitThreadPool"

parents 16bb6dcd e29a5a11
Loading
Loading
Loading
Loading
+89 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2016 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License
 */

package com.android.internal.util;

import android.os.Process;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * Utility methods for common functionality using java.util.concurrent package
 *
 * @hide
 */
public class ConcurrentUtils {

    private ConcurrentUtils() {
    }

    /**
     * Creates a thread pool using
     * {@link java.util.concurrent.Executors#newFixedThreadPool(int, ThreadFactory)}
     *
     * @param nThreads the number of threads in the pool
     * @param poolName base name of the threads in the pool
     * @param linuxThreadPriority a Linux priority level. see {@link Process#setThreadPriority(int)}
     * @return the newly created thread pool
     */
    public static ExecutorService newFixedThreadPool(int nThreads, String poolName,
            int linuxThreadPriority) {
        return Executors.newFixedThreadPool(nThreads,
                new ThreadFactory() {
                    private final AtomicInteger threadNum = new AtomicInteger(0);

                    @Override
                    public Thread newThread(final Runnable r) {
                        return new Thread(poolName + threadNum.incrementAndGet()) {
                            @Override
                            public void run() {
                                Process.setThreadPriority(linuxThreadPriority);
                                r.run();
                            }
                        };
                    }
                });
    }

    /**
     * Waits if necessary for the computation to complete, and then retrieves its result.
     * <p>If {@code InterruptedException} occurs, this method will interrupt the current thread
     * and throw {@code IllegalStateException}</p>
     *
     * @param future future to wait for result
     * @param description short description of the operation
     * @return the computed result
     * @throws IllegalStateException if interrupted during wait
     * @throws RuntimeException if an error occurs while waiting for {@link Future#get()}
     * @see Future#get()
     */
    public static <T> T waitForFutureNoInterrupt(Future<T> future, String description) {
        try {
            return future.get();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new IllegalStateException(description + " interrupted");
        } catch (ExecutionException e) {
            throw new RuntimeException(description + " failed", e);
        }
    }

}
+2 −2
Original line number Diff line number Diff line
@@ -116,12 +116,12 @@ public class PersistentDataBlockService extends SystemService {
    @Override
    public void onStart() {
        // Do init on a separate thread, will join in PHASE_ACTIVITY_MANAGER_READY
        FgThread.getHandler().post(() -> {
        SystemServerInitThreadPool.get().submit(() -> {
            enforceChecksumValidity();
            formatIfOemUnlockEnabled();
            publishBinderService(Context.PERSISTENT_DATA_BLOCK_SERVICE, mService);
            mInitDoneSignal.countDown();
        });
        }, TAG + ".onStart");
    }

    @Override
+96 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2016 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License
 */

package com.android.server;

import android.os.Build;
import android.os.Process;
import android.util.Slog;

import com.android.internal.util.ConcurrentUtils;
import com.android.internal.util.Preconditions;

import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

/**
 * Thread pool used during initialization of system server.
 * <p>System services can {@link #submit(Runnable)} tasks for execution during boot.
 * The pool will be shut down after {@link SystemService#PHASE_BOOT_COMPLETED}.
 * New tasks <em>should not</em> be submitted afterwards.
 *
 * @hide
 */
public class SystemServerInitThreadPool {
    private static final String TAG = SystemServerInitThreadPool.class.getSimpleName();
    private static final int SHUTDOWN_TIMEOUT_MILLIS = 20000;
    private static final boolean IS_DEBUGGABLE = Build.IS_DEBUGGABLE;

    private static SystemServerInitThreadPool sInstance;

    private ExecutorService mService = ConcurrentUtils.newFixedThreadPool(2,
            "system-server-init-thread", Process.THREAD_PRIORITY_FOREGROUND);

    public static synchronized SystemServerInitThreadPool get() {
        if (sInstance == null) {
            sInstance = new SystemServerInitThreadPool();
        }
        Preconditions.checkState(sInstance.mService != null, "Cannot get " + TAG
                + " - it has been shut down");
        return sInstance;
    }

    public Future<?> submit(Runnable runnable, String description) {
        if (IS_DEBUGGABLE) {
            return mService.submit(() -> {
                Slog.d(TAG, "Started executing " + description);
                try {
                    runnable.run();
                } catch (RuntimeException e) {
                    Slog.e(TAG, "Failure in " + description + ": " + e, e);
                    throw e;
                }
                Slog.d(TAG, "Finished executing "  + description);
            });
        }
        return mService.submit(runnable);
    }

    static synchronized void shutdown() {
        if (sInstance != null && sInstance.mService != null) {
            sInstance.mService.shutdown();
            boolean terminated;
            try {
                terminated = sInstance.mService.awaitTermination(SHUTDOWN_TIMEOUT_MILLIS,
                        TimeUnit.MILLISECONDS);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                throw new IllegalStateException(TAG + " init interrupted");
            }
            List<Runnable> unstartedRunnables = sInstance.mService.shutdownNow();
            if (!terminated) {
                throw new IllegalStateException("Cannot shutdown. Unstarted tasks "
                        + unstartedRunnables);
            }
            sInstance.mService = null; // Make mService eligible for GC
            Slog.d(TAG, "Shutdown successful");
        }
    }

}
+6 −4
Original line number Diff line number Diff line
@@ -208,11 +208,13 @@ final class UiModeManagerService extends SystemService {
                Settings.Secure.UI_NIGHT_MODE, defaultNightMode);

        // Update the initial, static configurations.
        synchronized (this) {
        SystemServerInitThreadPool.get().submit(() -> {
            synchronized (mLock) {
                updateConfigurationLocked();
                sendConfigurationLocked();
            }

        }, TAG + ".onStart");
        publishBinderService(Context.UI_MODE_SERVICE, mService);
    }

+2 −2
Original line number Diff line number Diff line
@@ -54,7 +54,7 @@ import android.util.proto.ProtoOutputStream;

import com.android.internal.annotations.GuardedBy;
import com.android.internal.logging.MetricsLogger;
import com.android.server.FgThread;
import com.android.server.SystemServerInitThreadPool;
import com.android.server.SystemService;

import org.json.JSONArray;
@@ -1077,7 +1077,7 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
    @Override
    public void onStart() {
        publishBinderService(Context.FINGERPRINT_SERVICE, new FingerprintServiceWrapper());
        FgThread.getHandler().post(() -> getFingerprintDaemon());
        SystemServerInitThreadPool.get().submit(this::getFingerprintDaemon, TAG + ".onStart");
        listenForUserSwitches();
    }

Loading