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