Merge "Clean up system service registration. (2nd try)"
diff --git a/apex/blobstore/framework/java/android/app/blob/BlobStoreManagerFrameworkInitializer.java b/apex/blobstore/framework/java/android/app/blob/BlobStoreManagerFrameworkInitializer.java
index 6e6d6ae..56c419a 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 @@
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 c264531..0000000
--- 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 175e5f2..f3ec5e5 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 @@
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 4fb2196..33ea32b 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -18,6 +18,7 @@
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.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 @@
new ArrayMap<String, ServiceFetcher<?>>();
private static int sServiceCacheSize;
+ private static volatile boolean sInitializing;
+
// Not instantiable.
private SystemServiceRegistry() { }
@@ -1292,14 +1294,28 @@
}});
//CHECKSTYLE:ON IndentationCheck
- JobSchedulerFrameworkInitializer.initialize();
- DeviceIdleFrameworkInitializer.initialize();
+ sInitializing = true;
+ try {
+ // Note: the following functions need to be @SystemApis, once they become mainline
+ // modules.
- BlobStoreManagerFrameworkInitializer.initialize();
+ 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 @@
/**
* 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 @@
/**
* 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 @@
* 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
*/
- public static <T> void registerStaticService(String serviceName, Class<T> serviceWrapperClass,
- Function<IBinder, T> serviceFetcher) {
+ //@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
+ */
+ //@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 CachedServiceFetcher<T>() {
+ new StaticServiceFetcher<TServiceClass>() {
@Override
- public T createService(ContextImpl ctx) throws ServiceNotFoundException {
- IBinder b = ServiceManager.getServiceOrThrow(serviceName);
- return serviceFetcher.apply(ctx.getOuterContext(), b);
+ 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<TServiceClass>() {
+ @Override
+ public TServiceClass createService(ContextImpl ctx) {
+ return serviceProducer.createService(ctx.getOuterContext());
}});
}
@@ -1517,6 +1698,7 @@
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