summaryrefslogtreecommitdiffstats
path: root/services/core/java/com/android/server/SystemServiceManager.java
diff options
context:
space:
mode:
authorNarayan Kamath <narayan@google.com>2014-08-07 10:57:40 +0100
committerNarayan Kamath <narayan@google.com>2014-08-15 13:37:03 +0100
commit29564cd24589867f653cd22cabbaac6493cfc530 (patch)
treec5ee0b88f293d292d95012844097acd172a7a72a /services/core/java/com/android/server/SystemServiceManager.java
parentbdc78678dedc6b66b9584948b908cd8cf77c6b30 (diff)
downloadframeworks_base-29564cd24589867f653cd22cabbaac6493cfc530.zip
frameworks_base-29564cd24589867f653cd22cabbaac6493cfc530.tar.gz
frameworks_base-29564cd24589867f653cd22cabbaac6493cfc530.tar.bz2
Remove system_server classes from the boot image.
We set the system_server classpath in the environment (like we do with BOOTCLASSPATH). After the zygote forks the system_server, we dexopt the classpath (if needed) and then launch the system server with the correct PathClassLoader. This needed several small / medium refactorings : - The logic for connecting to installd is now in a separate class and belongs in the system_server. - SystemService / SystemServiceManager have now moved to classes.jar. They are only used from there, and since they use Class.forName, we want them to be loaded by the system_server classloader, and not the bootclassloader. - BootReceiver now moves to frameworks.jar, because it is used by ActivityThread and friends. bug: 16555230 Change-Id: Ic84f0b2baf611eeedff6d123cb7191bb0259e600
Diffstat (limited to 'services/core/java/com/android/server/SystemServiceManager.java')
-rw-r--r--services/core/java/com/android/server/SystemServiceManager.java227
1 files changed, 227 insertions, 0 deletions
diff --git a/services/core/java/com/android/server/SystemServiceManager.java b/services/core/java/com/android/server/SystemServiceManager.java
new file mode 100644
index 0000000..fda6479
--- /dev/null
+++ b/services/core/java/com/android/server/SystemServiceManager.java
@@ -0,0 +1,227 @@
+/*
+ * Copyright (C) 2013 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.content.Context;
+import android.util.Slog;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+
+/**
+ * Manages creating, starting, and other lifecycle events of
+ * {@link com.android.server.SystemService system services}.
+ *
+ * {@hide}
+ */
+public class SystemServiceManager {
+ private static final String TAG = "SystemServiceManager";
+
+ private final Context mContext;
+ private boolean mSafeMode;
+
+ // Services that should receive lifecycle events.
+ private final ArrayList<SystemService> mServices = new ArrayList<SystemService>();
+
+ private int mCurrentPhase = -1;
+
+ public SystemServiceManager(Context context) {
+ mContext = context;
+ }
+
+ /**
+ * Starts a service by class name.
+ *
+ * @return The service instance.
+ */
+ @SuppressWarnings("unchecked")
+ public SystemService startService(String className) {
+ final Class<SystemService> serviceClass;
+ try {
+ serviceClass = (Class<SystemService>)Class.forName(className);
+ } catch (ClassNotFoundException ex) {
+ Slog.i(TAG, "Starting " + className);
+ throw new RuntimeException("Failed to create service " + className
+ + ": service class not found, usually indicates that the caller should "
+ + "have called PackageManager.hasSystemFeature() to check whether the "
+ + "feature is available on this device before trying to start the "
+ + "services that implement it", ex);
+ }
+ return startService(serviceClass);
+ }
+
+ /**
+ * Creates and starts a system service. The class must be a subclass of
+ * {@link com.android.server.SystemService}.
+ *
+ * @param serviceClass A Java class that implements the SystemService interface.
+ * @return The service instance, never null.
+ * @throws RuntimeException if the service fails to start.
+ */
+ @SuppressWarnings("unchecked")
+ public <T extends SystemService> T startService(Class<T> serviceClass) {
+ final String name = serviceClass.getName();
+ Slog.i(TAG, "Starting " + name);
+
+ // Create the service.
+ if (!SystemService.class.isAssignableFrom(serviceClass)) {
+ throw new RuntimeException("Failed to create " + name
+ + ": service must extend " + SystemService.class.getName());
+ }
+ final T service;
+ try {
+ Constructor<T> constructor = serviceClass.getConstructor(Context.class);
+ service = constructor.newInstance(mContext);
+ } catch (InstantiationException ex) {
+ throw new RuntimeException("Failed to create service " + name
+ + ": service could not be instantiated", ex);
+ } catch (IllegalAccessException ex) {
+ throw new RuntimeException("Failed to create service " + name
+ + ": service must have a public constructor with a Context argument", ex);
+ } catch (NoSuchMethodException ex) {
+ throw new RuntimeException("Failed to create service " + name
+ + ": service must have a public constructor with a Context argument", ex);
+ } catch (InvocationTargetException ex) {
+ throw new RuntimeException("Failed to create service " + name
+ + ": service constructor threw an exception", ex);
+ }
+
+ // Register it.
+ mServices.add(service);
+
+ // Start it.
+ try {
+ service.onStart();
+ } catch (RuntimeException ex) {
+ throw new RuntimeException("Failed to start service " + name
+ + ": onStart threw an exception", ex);
+ }
+ return service;
+ }
+
+ /**
+ * Starts the specified boot phase for all system services that have been started up to
+ * this point.
+ *
+ * @param phase The boot phase to start.
+ */
+ public void startBootPhase(final int phase) {
+ if (phase <= mCurrentPhase) {
+ throw new IllegalArgumentException("Next phase must be larger than previous");
+ }
+ mCurrentPhase = phase;
+
+ Slog.i(TAG, "Starting phase " + mCurrentPhase);
+
+ final int serviceLen = mServices.size();
+ for (int i = 0; i < serviceLen; i++) {
+ final SystemService service = mServices.get(i);
+ try {
+ service.onBootPhase(mCurrentPhase);
+ } catch (Exception ex) {
+ throw new RuntimeException("Failed to boot service "
+ + service.getClass().getName()
+ + ": onBootPhase threw an exception during phase "
+ + mCurrentPhase, ex);
+ }
+ }
+ }
+
+ public void startUser(final int userHandle) {
+ final int serviceLen = mServices.size();
+ for (int i = 0; i < serviceLen; i++) {
+ final SystemService service = mServices.get(i);
+ try {
+ service.onStartUser(userHandle);
+ } catch (Exception ex) {
+ Slog.wtf(TAG, "Failure reporting start of user " + userHandle
+ + " to service " + service.getClass().getName(), ex);
+ }
+ }
+ }
+
+ public void switchUser(final int userHandle) {
+ final int serviceLen = mServices.size();
+ for (int i = 0; i < serviceLen; i++) {
+ final SystemService service = mServices.get(i);
+ try {
+ service.onSwitchUser(userHandle);
+ } catch (Exception ex) {
+ Slog.wtf(TAG, "Failure reporting switch of user " + userHandle
+ + " to service " + service.getClass().getName(), ex);
+ }
+ }
+ }
+
+ public void stopUser(final int userHandle) {
+ final int serviceLen = mServices.size();
+ for (int i = 0; i < serviceLen; i++) {
+ final SystemService service = mServices.get(i);
+ try {
+ service.onStopUser(userHandle);
+ } catch (Exception ex) {
+ Slog.wtf(TAG, "Failure reporting stop of user " + userHandle
+ + " to service " + service.getClass().getName(), ex);
+ }
+ }
+ }
+
+ public void cleanupUser(final int userHandle) {
+ final int serviceLen = mServices.size();
+ for (int i = 0; i < serviceLen; i++) {
+ final SystemService service = mServices.get(i);
+ try {
+ service.onCleanupUser(userHandle);
+ } catch (Exception ex) {
+ Slog.wtf(TAG, "Failure reporting cleanup of user " + userHandle
+ + " to service " + service.getClass().getName(), ex);
+ }
+ }
+ }
+
+ /** Sets the safe mode flag for services to query. */
+ public void setSafeMode(boolean safeMode) {
+ mSafeMode = safeMode;
+ }
+
+ /**
+ * Returns whether we are booting into safe mode.
+ * @return safe mode flag
+ */
+ public boolean isSafeMode() {
+ return mSafeMode;
+ }
+
+ /**
+ * Outputs the state of this manager to the System log.
+ */
+ public void dump() {
+ StringBuilder builder = new StringBuilder();
+ builder.append("Current phase: ").append(mCurrentPhase).append("\n");
+ builder.append("Services:\n");
+ final int startedLen = mServices.size();
+ for (int i = 0; i < startedLen; i++) {
+ final SystemService service = mServices.get(i);
+ builder.append("\t")
+ .append(service.getClass().getSimpleName())
+ .append("\n");
+ }
+
+ Slog.e(TAG, builder.toString());
+ }
+}