Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3350e9f7 authored by satayev's avatar satayev
Browse files

Disallow starting new system services after apex services are started.

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.

Bug: 192880996
Test: presubmit
Change-Id: I42a5a1745c7fc0784fa2fef554c3d6439fd4c7fb
parent a8693ecd
Loading
Loading
Loading
Loading
+21 −9
Original line number Diff line number Diff line
@@ -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;
@@ -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;

@@ -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();
@@ -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.
@@ -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() {
@@ -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() {
@@ -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!");
            }
+8 −6
Original line number Diff line number Diff line
@@ -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", "******************************************");
@@ -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");
@@ -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
    }

+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));
    }
}