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