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

Commit b880d880 authored by Jeff Brown's avatar Jeff Brown
Browse files

Make SystemService constructor take a Context.

This change simplifies the process of initializing a SystemService
by folding the onCreate() step back into the constructor.  It removes
some ambuiguity about what work should happen in the constructor and
should make it possible for services to retain most of their final
fields after refactoring into the new pattern.

Change-Id: I25f41af0321bc01898658ab44b369f9c5d16800b
parent d9f9da39
Loading
Loading
Loading
Loading
+38 −21
Original line number Diff line number Diff line
@@ -23,24 +23,24 @@ import android.os.ServiceManager;
/**
 * The base class for services running in the system process. Override and implement
 * the lifecycle event callback methods as needed.
 *
 * <p>
 * The lifecycle of a SystemService:
 *
 * {@link #onCreate(android.content.Context)} is called to initialize the
 * service.
 *
 * {@link #onStart()} is called to get the service running. It is common
 * for services to publish their Binder interface at this point. All required
 * dependencies are also assumed to be ready to use.
 *
 * Then {@link #onBootPhase(int)} is called as many times as there are boot phases
 * </p><ul>
 * <li>The constructor is called and provided with the system {@link Context}
 * to initialize the system service.
 * <li>{@link #onStart()} is called to get the service running.  The service should
 * publish its binder interface at this point using
 * {@link #publishBinderService(String, IBinder)}.  It may also publish additional
 * local interfaces that other services within the system server may use to access
 * privileged internal functions.
 * <li>Then {@link #onBootPhase(int)} is called as many times as there are boot phases
 * until {@link #PHASE_BOOT_COMPLETE} is sent, which is the last boot phase. Each phase
 * is an opportunity to do special work, like acquiring optional service dependencies,
 * waiting to see if SafeMode is enabled, or registering with a service that gets
 * started after this one.
 *
 * NOTE: All lifecycle methods are called from the same thread that created the
 * SystemService.
 * </ul><p>
 * NOTE: All lifecycle methods are called from the system server's main looper thread.
 * </p>
 *
 * {@hide}
 */
@@ -54,17 +54,34 @@ public abstract class SystemService {
    public static final int PHASE_THIRD_PARTY_APPS_CAN_START = 600;
    public static final int PHASE_BOOT_COMPLETE = 1000;

    private SystemServiceManager mManager;
    private Context mContext;
    private final Context mContext;

    final void init(Context context, SystemServiceManager manager) {
    /**
     * Initializes the system service.
     * <p>
     * Subclasses must define a single argument constructor that accepts the context
     * and passes it to super.
     * </p>
     *
     * @param context The system server context.
     */
    public SystemService(Context context) {
        mContext = context;
        mManager = manager;
        onCreate(context);
    }

    /**
     * Gets the system context.
     */
    public final Context getContext() {
        return mContext;
    }

    /**
     * Returns true if the system is running in safe mode.
     * TODO: we should define in which phase this becomes valid
     */
    public final boolean isSafeMode() {
        return mManager.isSafeMode();
        return getManager().isSafeMode();
    }

    /**
@@ -126,8 +143,8 @@ public abstract class SystemService {
        return LocalServices.getService(type);
    }

    public final Context getContext() {
        return mContext;
    private SystemServiceManager getManager() {
        return LocalServices.getService(SystemServiceManager.class);
    }

//    /**
+39 −47
Original line number Diff line number Diff line
@@ -17,14 +17,15 @@
package com.android.server;

import android.content.Context;
import android.util.Log;
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}s.
 * {@link com.android.server.SystemService system services}.
 *
 * {@hide}
 */
@@ -68,24 +69,43 @@ public class SystemServiceManager {
     */
    @SuppressWarnings("unchecked")
    public <T extends SystemService> T startService(Class<T> serviceClass) {
        final T serviceInstance = (T)createInstance(serviceClass);
        try {
            Slog.i(TAG, "Creating " + serviceClass.getSimpleName());
            serviceInstance.init(mContext, this);
        } catch (Throwable e) {
            throw new RuntimeException("Failed to create service " + serviceClass.getName(), e);
        }

        mServices.add(serviceInstance);
        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 {
            Slog.i(TAG, "Starting " + serviceClass.getSimpleName());
            serviceInstance.onStart();
        } catch (Throwable e) {
            throw new RuntimeException("Failed to start service " + serviceClass.getName(), e);
            service.onStart();
        } catch (RuntimeException ex) {
            throw new RuntimeException("Failed to start service " + name
                    + ": onStart threw an exception", ex);
        }

        return serviceInstance;
        return service;
    }

    /**
@@ -107,9 +127,11 @@ public class SystemServiceManager {
            final SystemService service = mServices.get(i);
            try {
                service.onBootPhase(mCurrentPhase);
            } catch (Throwable e) {
                reportWtf("Service " + service.getClass().getName() +
                        " threw an Exception processing boot phase " + mCurrentPhase, e);
            } catch (Exception ex) {
                throw new RuntimeException("Failed to boot service "
                        + service.getClass().getName()
                        + ": onBootPhase threw an exception during phase "
                        + mCurrentPhase, ex);
            }
        }
    }
@@ -144,34 +166,4 @@ public class SystemServiceManager {

        Slog.e(TAG, builder.toString());
    }

    private SystemService createInstance(Class<?> clazz) {
        // Make sure it's a type we expect
        if (!SystemService.class.isAssignableFrom(clazz)) {
            reportWtf("Class " + clazz.getName() + " does not extend " +
                    SystemService.class.getName());
        }

        try {
            return (SystemService) clazz.newInstance();
        } catch (InstantiationException e) {
            reportWtf("Class " + clazz.getName() + " is abstract", e);
        } catch (IllegalAccessException e) {
            reportWtf("Class " + clazz.getName() +
                    " must have a public no-arg constructor", e);
        }
        return null;
    }

    private static void reportWtf(String message) {
        reportWtf(message, null);
    }

    private static void reportWtf(String message, Throwable e) {
        Slog.i(TAG, "******************************");
        Log.wtf(TAG, message, e);

        // Make sure we die
        throw new RuntimeException(message, e);
    }
}
+5 −5
Original line number Diff line number Diff line
@@ -53,13 +53,13 @@ public class AppWidgetService extends SystemService {

    static final String TAG = "AppWidgetService";

    Context mContext;
    Handler mSaveStateHandler;
    final Context mContext;
    final Handler mSaveStateHandler;

    SparseArray<AppWidgetServiceImpl> mAppWidgetServices;
    final SparseArray<AppWidgetServiceImpl> mAppWidgetServices;

    @Override
    public void onCreate(Context context) {
    public AppWidgetService(Context context) {
        super(context);
        mContext = context;

        mSaveStateHandler = BackgroundThread.getHandler();
+14 −0
Original line number Diff line number Diff line
@@ -274,6 +274,20 @@ public class BackupManagerService extends IBackupManager.Stub {
    // Watch the device provisioning operation during setup
    ContentObserver mProvisionedObserver;

    public static final class Lifecycle extends SystemService {
        private final BackupManagerService mService;

        public Lifecycle(Context context) {
            super(context);
            mService = new BackupManagerService(context);
        }

        @Override
        public void onStart() {
            publishBinderService(Context.BACKUP_SERVICE, mService);
        }
    }

    class ProvisionedObserver extends ContentObserver {
        public ProvisionedObserver(Handler handler) {
            super(handler);
+0 −36
Original line number Diff line number Diff line
/*
 * 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.backup;

import android.content.Context;

import com.android.server.SystemService;

public class BackupManagerSystemService extends SystemService {
    private BackupManagerService mBackupManagerImpl;

    @Override
    public void onCreate(Context context) {
        mBackupManagerImpl = new BackupManagerService(context);
    }

    @Override
    public void onStart() {
        publishBinderService(Context.BACKUP_SERVICE, mBackupManagerImpl);
    }
}
Loading