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

Commit 05b14f53 authored by Makoto Onuki's avatar Makoto Onuki
Browse files

Clean up system service registration. (2nd try)

Bug: 143788029
Test: boot
Test: build/soong/soong_ui.bash --make-mode dist ANDROID_BUILDSPEC=vendor/google/build/app_build_spec.mk
(This build uses java 8, which caused a build failure at the first try)

Test: atest SystemUITests

Change-Id: I352df4e76c9a2e787c9b4216b26d8d5fc84ff369
parent b9a57da9
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;
@@ -194,10 +195,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}.
@@ -216,6 +216,8 @@ public final class SystemServiceRegistry {
            new ArrayMap<String, ServiceFetcher<?>>();
    private static int sServiceCacheSize;

    private static volatile boolean sInitializing;

    // Not instantiable.
    private SystemServiceRegistry() { }

@@ -1292,14 +1294,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];
@@ -1307,6 +1323,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);
@@ -1315,6 +1332,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);
@@ -1324,41 +1342,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<TServiceClass>() {
                    @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<TServiceClass>() {
                    @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<TServiceClass>() {
                    @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<TServiceClass>() {
                    @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());
                    }});
    }

@@ -1517,6 +1698,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