SystemServiceManager.java revision 9158825f9c41869689d6b1786d7c7aa8bdd524ce
1/*
2 * Copyright (C) 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server;
18
19import android.content.Context;
20import android.util.Log;
21import android.util.Slog;
22
23import java.util.ArrayList;
24
25/**
26 * Manages creating, starting, and other lifecycle events of system services.
27 */
28public class SystemServiceManager {
29    private static final String TAG = "SystemServiceManager";
30
31    private final Context mContext;
32    private boolean mSafeMode;
33
34    // Services that should receive lifecycle events.
35    private final ArrayList<SystemService> mServices = new ArrayList<SystemService>();
36
37    private int mCurrentPhase = -1;
38
39    public SystemServiceManager(Context context) {
40        mContext = context;
41    }
42
43    public void startService(String className) {
44        try {
45            startService(Class.forName(className));
46        } catch (ClassNotFoundException cnfe) {
47            Slog.i(TAG, className + " not available, ignoring.");
48        }
49    }
50
51    /**
52     * Creates and starts a system service. The class must be a subclass of
53     * {@link com.android.server.SystemService}.
54     *
55     * @param serviceClass A Java class that implements the SystemService interface.
56     * @throws RuntimeException if the service fails to start.
57     */
58    public void startService(Class<?> serviceClass) {
59        final SystemService serviceInstance = createInstance(serviceClass);
60        try {
61            Slog.i(TAG, "Creating " + serviceClass.getSimpleName());
62            serviceInstance.init(mContext, this);
63        } catch (Throwable e) {
64            throw new RuntimeException("Failed to create service " + serviceClass.getName(), e);
65        }
66
67        mServices.add(serviceInstance);
68
69        try {
70            Slog.i(TAG, "Starting " + serviceClass.getSimpleName());
71            serviceInstance.onStart();
72        } catch (Throwable e) {
73            throw new RuntimeException("Failed to start service " + serviceClass.getName(), e);
74        }
75    }
76
77    /**
78     * Starts the specified boot phase for all system services that have been started up to
79     * this point.
80     *
81     * @param phase The boot phase to start.
82     */
83    public void startBootPhase(final int phase) {
84        if (phase <= mCurrentPhase) {
85            throw new IllegalArgumentException("Next phase must be larger than previous");
86        }
87        mCurrentPhase = phase;
88
89        Slog.i(TAG, "Starting phase " + mCurrentPhase);
90
91        final int serviceLen = mServices.size();
92        for (int i = 0; i < serviceLen; i++) {
93            final SystemService service = mServices.get(i);
94            try {
95                service.onBootPhase(mCurrentPhase);
96            } catch (Throwable e) {
97                reportWtf("Service " + service.getClass().getName() +
98                        " threw an Exception processing boot phase " + mCurrentPhase, e);
99            }
100        }
101    }
102
103    /** Sets the safe mode flag for services to query. */
104    public void setSafeMode(boolean safeMode) {
105        mSafeMode = safeMode;
106    }
107
108    /**
109     * Returns whether we are booting into safe mode.
110     * @return safe mode flag
111     */
112    public boolean isSafeMode() {
113        return mSafeMode;
114    }
115
116    /**
117     * Outputs the state of this manager to the System log.
118     */
119    public void dump() {
120        StringBuilder builder = new StringBuilder();
121        builder.append("Current phase: ").append(mCurrentPhase).append("\n");
122        builder.append("Services:\n");
123        final int startedLen = mServices.size();
124        for (int i = 0; i < startedLen; i++) {
125            final SystemService service = mServices.get(i);
126            builder.append("\t")
127                    .append(service.getClass().getSimpleName())
128                    .append("\n");
129        }
130
131        Slog.e(TAG, builder.toString());
132    }
133
134    private SystemService createInstance(Class<?> clazz) {
135        // Make sure it's a type we expect
136        if (!SystemService.class.isAssignableFrom(clazz)) {
137            reportWtf("Class " + clazz.getName() + " does not extend " +
138                    SystemService.class.getName());
139        }
140
141        try {
142            return (SystemService) clazz.newInstance();
143        } catch (InstantiationException e) {
144            reportWtf("Class " + clazz.getName() + " is abstract", e);
145        } catch (IllegalAccessException e) {
146            reportWtf("Class " + clazz.getName() +
147                    " must have a public no-arg constructor", e);
148        }
149        return null;
150    }
151
152    private static void reportWtf(String message) {
153        reportWtf(message, null);
154    }
155
156    private static void reportWtf(String message, Throwable e) {
157        Slog.i(TAG, "******************************");
158        Log.wtf(TAG, message, e);
159
160        // Make sure we die
161        throw new RuntimeException(message, e);
162    }
163}
164