1 /*
2  * Copyright (C) 2014 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 
17 package com.android.systemui;
18 
19 import android.app.ActivityThread;
20 import android.app.Application;
21 import android.content.BroadcastReceiver;
22 import android.content.Context;
23 import android.content.Intent;
24 import android.content.IntentFilter;
25 import android.content.pm.ApplicationInfo;
26 import android.content.res.Configuration;
27 import android.os.Process;
28 import android.os.SystemProperties;
29 import android.os.Trace;
30 import android.os.UserHandle;
31 import android.util.Log;
32 import android.util.TimingsTraceLog;
33 import android.view.SurfaceControl;
34 
35 import com.android.internal.protolog.common.ProtoLog;
36 import com.android.systemui.dagger.ContextComponentHelper;
37 import com.android.systemui.dagger.GlobalRootComponent;
38 import com.android.systemui.dagger.SysUIComponent;
39 import com.android.systemui.dump.DumpManager;
40 import com.android.systemui.shared.system.ThreadedRendererCompat;
41 import com.android.systemui.util.NotificationChannels;
42 
43 import java.lang.reflect.Constructor;
44 import java.lang.reflect.InvocationTargetException;
45 
46 /**
47  * Application class for SystemUI.
48  */
49 public class SystemUIApplication extends Application implements
50         SystemUIAppComponentFactory.ContextInitializer {
51 
52     public static final String TAG = "SystemUIService";
53     private static final boolean DEBUG = false;
54 
55     private ContextComponentHelper mComponentHelper;
56     private BootCompleteCacheImpl mBootCompleteCache;
57 
58     /**
59      * Hold a reference on the stuff we start.
60      */
61     private SystemUI[] mServices;
62     private boolean mServicesStarted;
63     private SystemUIAppComponentFactory.ContextAvailableCallback mContextAvailableCallback;
64     private GlobalRootComponent mRootComponent;
65     private SysUIComponent mSysUIComponent;
66 
SystemUIApplication()67     public SystemUIApplication() {
68         super();
69         Log.v(TAG, "SystemUIApplication constructed.");
70         // SysUI may be building without protolog preprocessing in some cases
71         ProtoLog.REQUIRE_PROTOLOGTOOL = false;
72     }
73 
74     @Override
onCreate()75     public void onCreate() {
76         super.onCreate();
77         Log.v(TAG, "SystemUIApplication created.");
78         // This line is used to setup Dagger's dependency injection and should be kept at the
79         // top of this method.
80         TimingsTraceLog log = new TimingsTraceLog("SystemUIBootTiming",
81                 Trace.TRACE_TAG_APP);
82         log.traceBegin("DependencyInjection");
83         mContextAvailableCallback.onContextAvailable(this);
84         mRootComponent = SystemUIFactory.getInstance().getRootComponent();
85         mSysUIComponent = SystemUIFactory.getInstance().getSysUIComponent();
86         mComponentHelper = mSysUIComponent.getContextComponentHelper();
87         mBootCompleteCache = mSysUIComponent.provideBootCacheImpl();
88         log.traceEnd();
89 
90         // Set the application theme that is inherited by all services. Note that setting the
91         // application theme in the manifest does only work for activities. Keep this in sync with
92         // the theme set there.
93         setTheme(R.style.Theme_SystemUI);
94 
95         if (Process.myUserHandle().equals(UserHandle.SYSTEM)) {
96             IntentFilter bootCompletedFilter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED);
97             bootCompletedFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
98 
99             // If SF GPU context priority is set to realtime, then SysUI should run at high.
100             // The priority is defaulted at medium.
101             int sfPriority = SurfaceControl.getGPUContextPriority();
102             Log.i(TAG, "Found SurfaceFlinger's GPU Priority: " + sfPriority);
103             if (sfPriority == ThreadedRendererCompat.EGL_CONTEXT_PRIORITY_REALTIME_NV) {
104                 Log.i(TAG, "Setting SysUI's GPU Context priority to: "
105                         + ThreadedRendererCompat.EGL_CONTEXT_PRIORITY_HIGH_IMG);
106                 ThreadedRendererCompat.setContextPriority(
107                         ThreadedRendererCompat.EGL_CONTEXT_PRIORITY_HIGH_IMG);
108             }
109 
110             registerReceiver(new BroadcastReceiver() {
111                 @Override
112                 public void onReceive(Context context, Intent intent) {
113                     if (mBootCompleteCache.isBootComplete()) return;
114 
115                     if (DEBUG) Log.v(TAG, "BOOT_COMPLETED received");
116                     unregisterReceiver(this);
117                     mBootCompleteCache.setBootComplete();
118                     if (mServicesStarted) {
119                         final int N = mServices.length;
120                         for (int i = 0; i < N; i++) {
121                             mServices[i].onBootCompleted();
122                         }
123                     }
124                 }
125             }, bootCompletedFilter);
126 
127             IntentFilter localeChangedFilter = new IntentFilter(Intent.ACTION_LOCALE_CHANGED);
128             registerReceiver(new BroadcastReceiver() {
129                 @Override
130                 public void onReceive(Context context, Intent intent) {
131                     if (Intent.ACTION_LOCALE_CHANGED.equals(intent.getAction())) {
132                         if (!mBootCompleteCache.isBootComplete()) return;
133                         // Update names of SystemUi notification channels
134                         NotificationChannels.createAll(context);
135                     }
136                 }
137             }, localeChangedFilter);
138         } else {
139             // We don't need to startServices for sub-process that is doing some tasks.
140             // (screenshots, sweetsweetdesserts or tuner ..)
141             String processName = ActivityThread.currentProcessName();
142             ApplicationInfo info = getApplicationInfo();
143             if (processName != null && processName.startsWith(info.processName + ":")) {
144                 return;
145             }
146             // For a secondary user, boot-completed will never be called because it has already
147             // been broadcasted on startup for the primary SystemUI process.  Instead, for
148             // components which require the SystemUI component to be initialized per-user, we
149             // start those components now for the current non-system user.
150             startSecondaryUserServicesIfNeeded();
151         }
152     }
153 
154     /**
155      * Makes sure that all the SystemUI services are running. If they are already running, this is a
156      * no-op. This is needed to conditinally start all the services, as we only need to have it in
157      * the main process.
158      * <p>This method must only be called from the main thread.</p>
159      */
160 
startServicesIfNeeded()161     public void startServicesIfNeeded() {
162         String[] names = SystemUIFactory.getInstance().getSystemUIServiceComponents(getResources());
163         startServicesIfNeeded(/* metricsPrefix= */ "StartServices", names);
164     }
165 
166     /**
167      * Ensures that all the Secondary user SystemUI services are running. If they are already
168      * running, this is a no-op. This is needed to conditionally start all the services, as we only
169      * need to have it in the main process.
170      * <p>This method must only be called from the main thread.</p>
171      */
startSecondaryUserServicesIfNeeded()172     void startSecondaryUserServicesIfNeeded() {
173         String[] names = SystemUIFactory.getInstance().getSystemUIServiceComponentsPerUser(
174                 getResources());
175         startServicesIfNeeded(/* metricsPrefix= */ "StartSecondaryServices", names);
176     }
177 
startServicesIfNeeded(String metricsPrefix, String[] services)178     private void startServicesIfNeeded(String metricsPrefix, String[] services) {
179         if (mServicesStarted) {
180             return;
181         }
182         mServices = new SystemUI[services.length];
183 
184         if (!mBootCompleteCache.isBootComplete()) {
185             // check to see if maybe it was already completed long before we began
186             // see ActivityManagerService.finishBooting()
187             if ("1".equals(SystemProperties.get("sys.boot_completed"))) {
188                 mBootCompleteCache.setBootComplete();
189                 if (DEBUG) {
190                     Log.v(TAG, "BOOT_COMPLETED was already sent");
191                 }
192             }
193         }
194 
195         final DumpManager dumpManager = mSysUIComponent.createDumpManager();
196 
197         Log.v(TAG, "Starting SystemUI services for user " +
198                 Process.myUserHandle().getIdentifier() + ".");
199         TimingsTraceLog log = new TimingsTraceLog("SystemUIBootTiming",
200                 Trace.TRACE_TAG_APP);
201         log.traceBegin(metricsPrefix);
202         final int N = services.length;
203         for (int i = 0; i < N; i++) {
204             String clsName = services[i];
205             if (DEBUG) Log.d(TAG, "loading: " + clsName);
206             log.traceBegin(metricsPrefix + clsName);
207             long ti = System.currentTimeMillis();
208             try {
209                 SystemUI obj = mComponentHelper.resolveSystemUI(clsName);
210                 if (obj == null) {
211                     Constructor constructor = Class.forName(clsName).getConstructor(Context.class);
212                     obj = (SystemUI) constructor.newInstance(this);
213                 }
214                 mServices[i] = obj;
215             } catch (ClassNotFoundException
216                     | NoSuchMethodException
217                     | IllegalAccessException
218                     | InstantiationException
219                     | InvocationTargetException ex) {
220                 throw new RuntimeException(ex);
221             }
222 
223             if (DEBUG) Log.d(TAG, "running: " + mServices[i]);
224             mServices[i].start();
225             log.traceEnd();
226 
227             // Warn if initialization of component takes too long
228             ti = System.currentTimeMillis() - ti;
229             if (ti > 1000) {
230                 Log.w(TAG, "Initialization of " + clsName + " took " + ti + " ms");
231             }
232             if (mBootCompleteCache.isBootComplete()) {
233                 mServices[i].onBootCompleted();
234             }
235 
236             dumpManager.registerDumpable(mServices[i].getClass().getName(), mServices[i]);
237         }
238         mSysUIComponent.getInitController().executePostInitTasks();
239         log.traceEnd();
240 
241         mServicesStarted = true;
242     }
243 
244     @Override
onConfigurationChanged(Configuration newConfig)245     public void onConfigurationChanged(Configuration newConfig) {
246         if (mServicesStarted) {
247             mSysUIComponent.getConfigurationController().onConfigurationChanged(newConfig);
248             int len = mServices.length;
249             for (int i = 0; i < len; i++) {
250                 if (mServices[i] != null) {
251                     mServices[i].onConfigurationChanged(newConfig);
252                 }
253             }
254         }
255     }
256 
getServices()257     public SystemUI[] getServices() {
258         return mServices;
259     }
260 
261     @Override
setContextAvailableCallback( SystemUIAppComponentFactory.ContextAvailableCallback callback)262     public void setContextAvailableCallback(
263             SystemUIAppComponentFactory.ContextAvailableCallback callback) {
264         mContextAvailableCallback = callback;
265     }
266 
267 }
268