Loading services/core/java/com/android/server/SystemServiceManager.java +21 −9 Original line number Diff line number Diff line Loading @@ -45,6 +45,8 @@ import java.io.File; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; Loading Loading @@ -91,7 +93,7 @@ public final class SystemServiceManager implements Dumpable { private long mRuntimeStartUptime; // Services that should receive lifecycle events. private final ArrayList<SystemService> mServices = new ArrayList<SystemService>(); private List<SystemService> mServices; private int mCurrentPhase = -1; Loading @@ -113,6 +115,7 @@ public final class SystemServiceManager implements Dumpable { SystemServiceManager(Context context) { mContext = context; mServices = new ArrayList<>(); // Disable using the thread pool for low ram devices sUseLifecycleThreadPool = sUseLifecycleThreadPool && !ActivityManager.isLowRamDeviceStatic(); Loading Loading @@ -220,6 +223,11 @@ public final class SystemServiceManager implements Dumpable { warnIfTooLong(SystemClock.elapsedRealtime() - time, service, "onStart"); } /** Disallow starting new services after this call. */ void sealStartedServices() { mServices = Collections.unmodifiableList(mServices); } /** * Starts the specified boot phase for all system services that have been started up to * this point. Loading Loading @@ -516,6 +524,7 @@ public final class SystemServiceManager implements Dumpable { /** * Returns whether we are booting into safe mode. * * @return safe mode flag */ public boolean isSafeMode() { Loading Loading @@ -559,9 +568,10 @@ public final class SystemServiceManager implements Dumpable { /** * Ensures that the system directory exist creating one if needed. * * @return The system directory. * @deprecated Use {@link Environment#getDataSystemCeDirectory()} * or {@link Environment#getDataSystemDeDirectory()} instead. * @return The system directory. */ @Deprecated public static File ensureSystemDir() { Loading @@ -578,7 +588,9 @@ public final class SystemServiceManager implements Dumpable { pw.printf("Current phase: %d\n", mCurrentPhase); synchronized (mTargetUsers) { if (mCurrentUser != null) { pw.print("Current user: "); mCurrentUser.dump(pw); pw.println(); pw.print("Current user: "); mCurrentUser.dump(pw); pw.println(); } else { pw.println("Current user not set!"); } Loading services/java/com/android/server/SystemServer.java +8 −6 Original line number Diff line number Diff line Loading @@ -920,12 +920,6 @@ public final class SystemServer implements Dumpable { startBootstrapServices(t); startCoreServices(t); startOtherServices(t); // Apex services must be the last category of services to start. No other service must // be starting after this point. This is to prevent unnessary stability issues when // these apexes are updated outside of OTA; and to avoid breaking dependencies from // system into apexes. // TODO(satayev): lock mSystemServiceManager.startService to stop accepting new services // after this step startApexServices(t); } catch (Throwable ex) { Slog.e("System", "******************************************"); Loading Loading @@ -3051,6 +3045,10 @@ public final class SystemServer implements Dumpable { /** * Starts system services defined in apexes. * * <p>Apex services must be the last category of services to start. No other service must be * starting after this point. This is to prevent unnecessary stability issues when these apexes * are updated outside of OTA; and to avoid breaking dependencies from system into apexes. */ private void startApexServices(@NonNull TimingsTraceAndSlog t) { t.traceBegin("startApexServices"); Loading @@ -3067,6 +3065,10 @@ public final class SystemServer implements Dumpable { } t.traceEnd(); } // make sure no other services are started after this point mSystemServiceManager.sealStartedServices(); t.traceEnd(); // startApexServices } Loading services/tests/servicestests/src/com/android/server/SystemServiceManagerTest.java 0 → 100644 +55 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 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 static org.junit.Assert.assertThrows; import android.test.AndroidTestCase; import org.junit.Test; import java.util.concurrent.atomic.AtomicBoolean; /** * Tests for {@link SystemServiceManager}. */ public class SystemServiceManagerTest extends AndroidTestCase { private static final String TAG = "SystemServiceManagerTest"; @Test public void testSealStartedServices() throws Exception { SystemServiceManager manager = new SystemServiceManager(getContext()); // must be effectively final, since it's changed from inner class below AtomicBoolean serviceStarted = new AtomicBoolean(false); SystemService service = new SystemService(getContext()) { @Override public void onStart() { serviceStarted.set(true); } }; // started services have their #onStart methods called manager.startService(service); assertTrue(serviceStarted.get()); // however, after locking started services, it is not possible to start a new service manager.sealStartedServices(); assertThrows(UnsupportedOperationException.class, () -> manager.startService(service)); } } Loading
services/core/java/com/android/server/SystemServiceManager.java +21 −9 Original line number Diff line number Diff line Loading @@ -45,6 +45,8 @@ import java.io.File; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; Loading Loading @@ -91,7 +93,7 @@ public final class SystemServiceManager implements Dumpable { private long mRuntimeStartUptime; // Services that should receive lifecycle events. private final ArrayList<SystemService> mServices = new ArrayList<SystemService>(); private List<SystemService> mServices; private int mCurrentPhase = -1; Loading @@ -113,6 +115,7 @@ public final class SystemServiceManager implements Dumpable { SystemServiceManager(Context context) { mContext = context; mServices = new ArrayList<>(); // Disable using the thread pool for low ram devices sUseLifecycleThreadPool = sUseLifecycleThreadPool && !ActivityManager.isLowRamDeviceStatic(); Loading Loading @@ -220,6 +223,11 @@ public final class SystemServiceManager implements Dumpable { warnIfTooLong(SystemClock.elapsedRealtime() - time, service, "onStart"); } /** Disallow starting new services after this call. */ void sealStartedServices() { mServices = Collections.unmodifiableList(mServices); } /** * Starts the specified boot phase for all system services that have been started up to * this point. Loading Loading @@ -516,6 +524,7 @@ public final class SystemServiceManager implements Dumpable { /** * Returns whether we are booting into safe mode. * * @return safe mode flag */ public boolean isSafeMode() { Loading Loading @@ -559,9 +568,10 @@ public final class SystemServiceManager implements Dumpable { /** * Ensures that the system directory exist creating one if needed. * * @return The system directory. * @deprecated Use {@link Environment#getDataSystemCeDirectory()} * or {@link Environment#getDataSystemDeDirectory()} instead. * @return The system directory. */ @Deprecated public static File ensureSystemDir() { Loading @@ -578,7 +588,9 @@ public final class SystemServiceManager implements Dumpable { pw.printf("Current phase: %d\n", mCurrentPhase); synchronized (mTargetUsers) { if (mCurrentUser != null) { pw.print("Current user: "); mCurrentUser.dump(pw); pw.println(); pw.print("Current user: "); mCurrentUser.dump(pw); pw.println(); } else { pw.println("Current user not set!"); } Loading
services/java/com/android/server/SystemServer.java +8 −6 Original line number Diff line number Diff line Loading @@ -920,12 +920,6 @@ public final class SystemServer implements Dumpable { startBootstrapServices(t); startCoreServices(t); startOtherServices(t); // Apex services must be the last category of services to start. No other service must // be starting after this point. This is to prevent unnessary stability issues when // these apexes are updated outside of OTA; and to avoid breaking dependencies from // system into apexes. // TODO(satayev): lock mSystemServiceManager.startService to stop accepting new services // after this step startApexServices(t); } catch (Throwable ex) { Slog.e("System", "******************************************"); Loading Loading @@ -3051,6 +3045,10 @@ public final class SystemServer implements Dumpable { /** * Starts system services defined in apexes. * * <p>Apex services must be the last category of services to start. No other service must be * starting after this point. This is to prevent unnecessary stability issues when these apexes * are updated outside of OTA; and to avoid breaking dependencies from system into apexes. */ private void startApexServices(@NonNull TimingsTraceAndSlog t) { t.traceBegin("startApexServices"); Loading @@ -3067,6 +3065,10 @@ public final class SystemServer implements Dumpable { } t.traceEnd(); } // make sure no other services are started after this point mSystemServiceManager.sealStartedServices(); t.traceEnd(); // startApexServices } Loading
services/tests/servicestests/src/com/android/server/SystemServiceManagerTest.java 0 → 100644 +55 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 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 static org.junit.Assert.assertThrows; import android.test.AndroidTestCase; import org.junit.Test; import java.util.concurrent.atomic.AtomicBoolean; /** * Tests for {@link SystemServiceManager}. */ public class SystemServiceManagerTest extends AndroidTestCase { private static final String TAG = "SystemServiceManagerTest"; @Test public void testSealStartedServices() throws Exception { SystemServiceManager manager = new SystemServiceManager(getContext()); // must be effectively final, since it's changed from inner class below AtomicBoolean serviceStarted = new AtomicBoolean(false); SystemService service = new SystemService(getContext()) { @Override public void onStart() { serviceStarted.set(true); } }; // started services have their #onStart methods called manager.startService(service); assertTrue(serviceStarted.get()); // however, after locking started services, it is not possible to start a new service manager.sealStartedServices(); assertThrows(UnsupportedOperationException.class, () -> manager.startService(service)); } }