diff options
4 files changed, 226 insertions, 59 deletions
diff --git a/apex/blobstore/framework/java/android/app/blob/BlobStoreManagerFrameworkInitializer.java b/apex/blobstore/framework/java/android/app/blob/BlobStoreManagerFrameworkInitializer.java index 6e6d6aee60fa..56c419ab0591 100644 --- a/apex/blobstore/framework/java/android/app/blob/BlobStoreManagerFrameworkInitializer.java +++ b/apex/blobstore/framework/java/android/app/blob/BlobStoreManagerFrameworkInitializer.java @@ -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))); diff --git a/apex/jobscheduler/framework/java/android/app/DeviceIdleFrameworkInitializer.java b/apex/jobscheduler/framework/java/android/app/DeviceIdleFrameworkInitializer.java deleted file mode 100644 index c264531c3947..000000000000 --- a/apex/jobscheduler/framework/java/android/app/DeviceIdleFrameworkInitializer.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * 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))); - } -} diff --git a/apex/jobscheduler/framework/java/android/app/job/JobSchedulerFrameworkInitializer.java b/apex/jobscheduler/framework/java/android/app/job/JobSchedulerFrameworkInitializer.java index 175e5f23f761..f3ec5e5752a0 100644 --- a/apex/jobscheduler/framework/java/android/app/job/JobSchedulerFrameworkInitializer.java +++ b/apex/jobscheduler/framework/java/android/app/job/JobSchedulerFrameworkInitializer.java @@ -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))); } } diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java index 4fb2196d4e26..33ea32b7e31e 100644 --- a/core/java/android/app/SystemServiceRegistry.java +++ b/core/java/android/app/SystemServiceRegistry.java @@ -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(); - - BlobStoreManagerFrameworkInitializer.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 */ - public static <T> void registerStaticService(String serviceName, Class<T> serviceWrapperClass, - Function<IBinder, T> serviceFetcher) { + //@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 + */ + //@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 |