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

Commit 3212ad01 authored by Makoto Onuki's avatar Makoto Onuki Committed by Android (Google) Code Review
Browse files

Merge "Clean up system service registration."

parents be3930b7 a9f22240
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -26,7 +26,7 @@ import android.content.Context;
public class BlobStoreManagerFrameworkInitializer {
    /** Register the BlobStoreManager wrapper class */
    public static void initialize() {
        SystemServiceRegistry.registerCachedService(
        SystemServiceRegistry.registerContextAwareService(
                Context.BLOB_STORE_SERVICE, BlobStoreManager.class,
                (context, service) ->
                        new BlobStoreManager(context, IBlobStoreManager.Stub.asInterface(service)));
+0 −35
Original line number Diff line number Diff line
/*
 * Copyright (C) 2019 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 android.app;

import android.content.Context;
import android.os.DeviceIdleManager;
import android.os.IDeviceIdleController;

/**
 * @hide
 */
public class DeviceIdleFrameworkInitializer {
    private static IDeviceIdleController sIDeviceIdleController;

    public static void initialize() {
        SystemServiceRegistry.registerCachedService(
                Context.DEVICE_IDLE_CONTROLLER, DeviceIdleManager.class,
                (context, b) -> new DeviceIdleManager(
                        context, IDeviceIdleController.Stub.asInterface(b)));
    }
}
+21 −1
Original line number Diff line number Diff line
@@ -19,14 +19,34 @@ package android.app.job;
import android.app.JobSchedulerImpl;
import android.app.SystemServiceRegistry;
import android.content.Context;
import android.os.DeviceIdleManager;
import android.os.IDeviceIdleController;

/**
 * Class holding initialization code for the job scheduler module.
 *
 * @hide
 */
public class JobSchedulerFrameworkInitializer {
    public static void initialize() {
    private JobSchedulerFrameworkInitializer() {
    }

    /**
     * Called by {@link SystemServiceRegistry}'s static initializer and registers
     * {@link JobScheduler} and other services to {@link Context}, so
     * {@link Context#getSystemService} can return them.
     *
     * <p>If this is called from other places, it throws a {@link IllegalStateException).
     *
     * TODO Make it a system API
     */
    public static void registerServiceWrappers() {
        SystemServiceRegistry.registerStaticService(
                Context.JOB_SCHEDULER_SERVICE, JobScheduler.class,
                (b) -> new JobSchedulerImpl(IJobScheduler.Stub.asInterface(b)));
        SystemServiceRegistry.registerContextAwareService(
                Context.DEVICE_IDLE_CONTROLLER, DeviceIdleManager.class,
                (context, b) -> new DeviceIdleManager(
                        context, IDeviceIdleController.Stub.asInterface(b)));
    }
}
+204 −22
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package android.app;

import android.accounts.AccountManager;
import android.accounts.IAccountManager;
import android.annotation.NonNull;
import android.app.ContextImpl.ServiceInitializationState;
import android.app.admin.DevicePolicyManager;
import android.app.admin.IDevicePolicyManager;
@@ -196,10 +197,9 @@ import com.android.internal.appwidget.IAppWidgetService;
import com.android.internal.net.INetworkWatchlistManager;
import com.android.internal.os.IDropBoxManagerService;
import com.android.internal.policy.PhoneLayoutInflater;
import com.android.internal.util.Preconditions;

import java.util.Map;
import java.util.function.BiFunction;
import java.util.function.Function;

/**
 * Manages all of the system services that can be returned by {@link Context#getSystemService}.
@@ -218,6 +218,8 @@ public final class SystemServiceRegistry {
            new ArrayMap<String, ServiceFetcher<?>>();
    private static int sServiceCacheSize;

    private static volatile boolean sInitializing;

    // Not instantiable.
    private SystemServiceRegistry() { }

@@ -1310,14 +1312,28 @@ public final class SystemServiceRegistry {
                    }});
        //CHECKSTYLE:ON IndentationCheck

        JobSchedulerFrameworkInitializer.initialize();
        DeviceIdleFrameworkInitializer.initialize();
        sInitializing = true;
        try {
            // Note: the following functions need to be @SystemApis, once they become mainline
            // modules.

            JobSchedulerFrameworkInitializer.registerServiceWrappers();
            BlobStoreManagerFrameworkInitializer.initialize();
        } finally {
            // If any of the above code throws, we're in a pretty bad shape and the process
            // will likely crash, but we'll reset it just in case there's an exception handler...
            sInitializing = false;
        }
    }

    /** Throws {@link IllegalStateException} if not during a static initialization. */
    private static void ensureInitializing(String methodName) {
        Preconditions.checkState(sInitializing, "Internal error: " + methodName
                + " can only be called during class initialization.");
    }
    /**
     * Creates an array which is used to cache per-Context service instances.
     * @hide
     */
    public static Object[] createServiceCache() {
        return new Object[sServiceCacheSize];
@@ -1325,6 +1341,7 @@ public final class SystemServiceRegistry {

    /**
     * Gets a system service from a given context.
     * @hide
     */
    public static Object getSystemService(ContextImpl ctx, String name) {
        ServiceFetcher<?> fetcher = SYSTEM_SERVICE_FETCHERS.get(name);
@@ -1333,6 +1350,7 @@ public final class SystemServiceRegistry {

    /**
     * Gets the name of the system-level service that is represented by the specified class.
     * @hide
     */
    public static String getSystemServiceName(Class<?> serviceClass) {
        return SYSTEM_SERVICE_NAMES.get(serviceClass);
@@ -1342,41 +1360,204 @@ public final class SystemServiceRegistry {
     * Statically registers a system service with the context.
     * This method must be called during static initialization only.
     */
    private static <T> void registerService(String serviceName, Class<T> serviceClass,
            ServiceFetcher<T> serviceFetcher) {
    private static <T> void registerService(@NonNull String serviceName,
            @NonNull Class<T> serviceClass, @NonNull ServiceFetcher<T> serviceFetcher) {
        SYSTEM_SERVICE_NAMES.put(serviceClass, serviceName);
        SYSTEM_SERVICE_FETCHERS.put(serviceName, serviceFetcher);
    }

    /**
     * APEX modules will use it to register their service wrapper.
     * Callback interface used as a parameter to {@link #registerStaticService(
     * String, Class, StaticServiceProducerNoBinder)}, which generates a service wrapper instance
     * that's not tied to any context and does not take a service binder object in the constructor.
     *
     * @param <TServiceClass> type of the service wrapper class.
     *
     * @hide
     */
    //@SystemApi TODO Make it a system API.
    public interface StaticServiceProducerNoBinder<TServiceClass> {
        /**
         * Return a new service wrapper of type {@code TServiceClass}.
         */
        TServiceClass createService();
    }

    /**
     * Callback interface used as a parameter to {@link #registerStaticService(
     * String, Class, StaticServiceProducerWithBinder)}, which generates a service wrapper instance
     * that's not tied to any context and takes a service binder object in the constructor.
     *
     * @param <TServiceClass> type of the service wrapper class.
     *
     * @hide
     */
    //@SystemApi TODO Make it a system API.
    public interface StaticServiceProducerWithBinder<TServiceClass> {
        /**
         * Return a new service wrapper of type {@code TServiceClass} backed by a given
         * service binder object.
         */
        TServiceClass createService(IBinder serviceBinder);
    }

    /**
     * Callback interface used as a parameter to {@link #registerContextAwareService(
     * String, Class, ContextAwareServiceProducerNoBinder)},
     * which generates a service wrapper instance
     * that's tied to a specific context and does not take a service binder object in the
     * constructor.
     *
     * @param <TServiceClass> type of the service wrapper class.
     *
     * @hide
     */
    //@SystemApi TODO Make it a system API.
    public interface ContextAwareServiceProducerNoBinder<TServiceClass> {
        /**
         * Return a new service wrapper of type {@code TServiceClass} tied to a given
         * {@code context}.
         *
         * TODO Do we need to pass the "base context" too?
         */
        TServiceClass createService(Context context);
    }

    /**
     * Callback interface used as a parameter to {@link #registerContextAwareService(
     * String, Class, ContextAwareServiceProducerWithBinder)},
     * which generates a service wrapper instance
     * that's tied to a specific context and takes a service binder object in the constructor.
     *
     * @param <TServiceClass> type of the service wrapper class.
     *
     * @hide
     */
    //@SystemApi TODO Make it a system API.
    public interface ContextAwareServiceProducerWithBinder<TServiceClass> {
        /**
         * Return a new service wrapper of type {@code TServiceClass} backed by a given
         * service binder object that's tied to a given {@code context}.
         *
         * TODO Do we need to pass the "base context" too?
         */
        TServiceClass createService(Context context, IBinder serviceBinder);
    }

    /**
     * Used by apex modules to register a "service wrapper" that is not tied to any {@link Context}.
     *
     * <p>This can only be called from the methods called by the static initializer of
     * {@link SystemServiceRegistry}. (Otherwise it throws a {@link IllegalStateException}.)
     *
     * @param serviceName the name of the binder object, such as
     *     {@link Context#JOB_SCHEDULER_SERVICE}.
     * @param serviceWrapperClass the wrapper class, such as the class of
     *     {@link android.app.job.JobScheduler}.
     * @param serviceProducer Callback that takes the service binder object with the name
     *     {@code serviceName} and returns an actual service wrapper instance.
     *
     * @hide
     */
    public static <T> void registerStaticService(String serviceName, Class<T> serviceWrapperClass,
            Function<IBinder, T> serviceFetcher) {
    //@SystemApi TODO Make it a system API.
    public static <TServiceClass> void registerStaticService(
            @NonNull String serviceName, @NonNull Class<TServiceClass> serviceWrapperClass,
            @NonNull StaticServiceProducerWithBinder<TServiceClass> serviceProducer) {
        ensureInitializing("registerStaticService");
        Preconditions.checkStringNotEmpty(serviceName);
        Preconditions.checkNotNull(serviceWrapperClass);
        Preconditions.checkNotNull(serviceProducer);

        registerService(serviceName, serviceWrapperClass,
                new StaticServiceFetcher<T>() {
                new StaticServiceFetcher<>() {
                    @Override
                    public T createService() throws ServiceNotFoundException {
                        IBinder b = ServiceManager.getServiceOrThrow(serviceName);
                        return serviceFetcher.apply(b);
                    public TServiceClass createService() throws ServiceNotFoundException {
                        return serviceProducer.createService(
                                ServiceManager.getServiceOrThrow(serviceName));
                    }});
    }

    /**
     * APEX modules will use it to register their service wrapper.
     * Similar to {@link #registerStaticService(String, Class, StaticServiceProducerWithBinder)},
     * but used for a "service wrapper" that doesn't take a service binder in its constructor.
     *
     * @hide
     */
    public static <T> void registerCachedService(String serviceName, Class<T> serviceWrapperClass,
            BiFunction<Context, IBinder, T> serviceFetcher) {
    //@SystemApi TODO Make it a system API.
    public static <TServiceClass> void registerStaticService(
            @NonNull String serviceName, @NonNull Class<TServiceClass> serviceWrapperClass,
            @NonNull StaticServiceProducerNoBinder<TServiceClass> serviceProducer) {
        ensureInitializing("registerStaticService");
        Preconditions.checkStringNotEmpty(serviceName);
        Preconditions.checkNotNull(serviceWrapperClass);
        Preconditions.checkNotNull(serviceProducer);

        registerService(serviceName, serviceWrapperClass,
                new StaticServiceFetcher<>() {
                    @Override
                    public TServiceClass createService() {
                        return serviceProducer.createService();
                    }});
    }

    /**
     * Used by apex modules to register a "service wrapper" that is tied to a specific
     * {@link Context}.
     *
     * <p>This can only be called from the methods called by the static initializer of
     * {@link SystemServiceRegistry}. (Otherwise it throws a {@link IllegalStateException}.)
     *
     * @param serviceName the name of the binder object, such as
     *     {@link Context#JOB_SCHEDULER_SERVICE}.
     * @param serviceWrapperClass the wrapper class, such as the class of
     *     {@link android.app.job.JobScheduler}.
     * @param serviceProducer lambda that takes the service binder object with the name
     *     {@code serviceName}, a {@link Context} and returns an actual service wrapper instance.
     *
     * @hide
     */
    //@SystemApi TODO Make it a system API.
    public static <TServiceClass> void registerContextAwareService(
            @NonNull String serviceName, @NonNull Class<TServiceClass> serviceWrapperClass,
            @NonNull ContextAwareServiceProducerWithBinder<TServiceClass> serviceProducer) {
        ensureInitializing("registerContextAwareService");
        Preconditions.checkStringNotEmpty(serviceName);
        Preconditions.checkNotNull(serviceWrapperClass);
        Preconditions.checkNotNull(serviceProducer);

        registerService(serviceName, serviceWrapperClass,
                new CachedServiceFetcher<>() {
                    @Override
                    public TServiceClass createService(ContextImpl ctx)
                            throws ServiceNotFoundException {
                        return serviceProducer.createService(
                                ctx.getOuterContext(),
                                ServiceManager.getServiceOrThrow(serviceName));
                    }});
    }


    /**
     * Similar to {@link #registerContextAwareService(String, Class,
     * ContextAwareServiceProducerWithBinder)},
     * but used for a "service wrapper" that doesn't take a service binder in its constructor.
     *
     * @hide
     */
    //@SystemApi TODO Make it a system API.
    public static <TServiceClass> void registerContextAwareService(
            @NonNull String serviceName, @NonNull Class<TServiceClass> serviceWrapperClass,
            @NonNull ContextAwareServiceProducerNoBinder<TServiceClass> serviceProducer) {
        ensureInitializing("registerContextAwareService");
        Preconditions.checkStringNotEmpty(serviceName);
        Preconditions.checkNotNull(serviceWrapperClass);
        Preconditions.checkNotNull(serviceProducer);

        registerService(serviceName, serviceWrapperClass,
                new CachedServiceFetcher<T>() {
                new CachedServiceFetcher<>() {
                    @Override
                    public T createService(ContextImpl ctx) throws ServiceNotFoundException {
                        IBinder b = ServiceManager.getServiceOrThrow(serviceName);
                        return serviceFetcher.apply(ctx.getOuterContext(), b);
                    public TServiceClass createService(ContextImpl ctx) {
                        return serviceProducer.createService(ctx.getOuterContext());
                    }});
    }

@@ -1535,6 +1716,7 @@ public final class SystemServiceRegistry {
        public abstract T createService(Context applicationContext) throws ServiceNotFoundException;
    }

    /** @hide */
    public static void onServiceNotFound(ServiceNotFoundException e) {
        // We're mostly interested in tracking down long-lived core system
        // components that might stumble if they obtain bad references; just