From b2d6884ecfb20706b6987b9edc9871fa5eb26309 Mon Sep 17 00:00:00 2001 From: Tej Singh Date: Wed, 8 Jan 2020 15:03:38 -0800 Subject: [PATCH] Dynamically load statsd-service Previously, service-statsd.jar was on the SYSTEM_SERVER_CLASSPATH. This CL loads StatsCompanion from SystemServer.java dynamically so that the jar does not have to be on the classpath. Bug: 146064616 Test: boots Change-Id: Ia0e98ed0b6e35da01b38ead2fcf45d440eae31c3 --- .../android/server/SystemServiceManager.java | 46 ++++++++++++++++--- .../java/com/android/server/SystemServer.java | 5 +- 2 files changed, 43 insertions(+), 8 deletions(-) diff --git a/services/core/java/com/android/server/SystemServiceManager.java b/services/core/java/com/android/server/SystemServiceManager.java index c7157981ada20..0b1449ce02dfb 100644 --- a/services/core/java/com/android/server/SystemServiceManager.java +++ b/services/core/java/com/android/server/SystemServiceManager.java @@ -25,10 +25,13 @@ import android.os.SystemClock; import android.os.Trace; import android.os.UserHandle; import android.os.UserManagerInternal; +import android.util.ArrayMap; import android.util.Slog; import com.android.server.utils.TimingsTraceAndSlog; +import dalvik.system.PathClassLoader; + import java.io.File; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; @@ -62,6 +65,9 @@ public class SystemServiceManager { // Services that should receive lifecycle events. private final ArrayList mServices = new ArrayList(); + // Map of paths to PathClassLoader, so we don't load the same path multiple times. + private final ArrayMap mLoadedPaths = new ArrayMap<>(); + private int mCurrentPhase = -1; private UserManagerInternal mUserManagerInternal; @@ -75,20 +81,46 @@ public class SystemServiceManager { * * @return The service instance. */ - @SuppressWarnings("unchecked") public SystemService startService(String className) { - final Class serviceClass; + final Class serviceClass = loadClassFromLoader(className, + this.getClass().getClassLoader()); + return startService(serviceClass); + } + + /** + * Starts a service by class name and a path that specifies the jar where the service lives. + * + * @return The service instance. + */ + public SystemService startServiceFromJar(String className, String path) { + PathClassLoader pathClassLoader = mLoadedPaths.get(path); + if (pathClassLoader == null) { + // NB: the parent class loader should always be the system server class loader. + // Changing it has implications that require discussion with the mainline team. + pathClassLoader = new PathClassLoader(path, this.getClass().getClassLoader()); + mLoadedPaths.put(path, pathClassLoader); + } + final Class serviceClass = loadClassFromLoader(className, pathClassLoader); + return startService(serviceClass); + } + + /* + * Loads and initializes a class from the given classLoader. Returns the class. + */ + @SuppressWarnings("unchecked") + private static Class loadClassFromLoader(String className, + ClassLoader classLoader) { try { - serviceClass = (Class)Class.forName(className); + return (Class) Class.forName(className, true, classLoader); } 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 " + + " from class loader " + classLoader.toString() + ": 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); + + "services that implement it. Also ensure that the correct path for the " + + "classloader is supplied, if applicable.", ex); } - return startService(serviceClass); } /** diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index cfe1318999871..7aee66e3cd7e1 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -212,6 +212,8 @@ public final class SystemServer { "com.android.server.print.PrintManagerService"; private static final String COMPANION_DEVICE_MANAGER_SERVICE_CLASS = "com.android.server.companion.CompanionDeviceManagerService"; + private static final String STATS_COMPANION_APEX_PATH = + "/apex/com.android.os.statsd/javalib/service-statsd.jar"; private static final String STATS_COMPANION_LIFECYCLE_CLASS = "com.android.server.stats.StatsCompanion$Lifecycle"; private static final String USB_SERVICE_CLASS = @@ -1972,7 +1974,8 @@ public final class SystemServer { // Statsd helper t.traceBegin("StartStatsCompanion"); - mSystemServiceManager.startService(STATS_COMPANION_LIFECYCLE_CLASS); + mSystemServiceManager.startServiceFromJar( + STATS_COMPANION_LIFECYCLE_CLASS, STATS_COMPANION_APEX_PATH); t.traceEnd(); // Incidentd and dumpstated helper