diff options
| author | 2017-04-04 03:41:50 +0000 | |
|---|---|---|
| committer | 2017-04-04 03:41:56 +0000 | |
| commit | dfc07c00521d51ff01dd3027e7ed5c872c486a65 (patch) | |
| tree | 2d3361468ec6c985ff0aaaf421cf14bd2f4e37c8 | |
| parent | 5dbb0f00472141da8128edf1a08f473ed7a0cd6e (diff) | |
| parent | bcc5b9f569356fa5076ca7348c40f521035a55d6 (diff) | |
Merge "Merge "Themes: Apply themes to system_server safely" into oc-dev am: a52fc49845 am: b188c93a45"
14 files changed, 119 insertions, 33 deletions
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index e49aad2cd607..d1d462c2fbe8 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -221,6 +221,7 @@ public final class ActivityThread { private long mNetworkBlockSeq = INVALID_PROC_STATE_SEQ; private ContextImpl mSystemContext; + private ContextImpl mSystemUiContext; static volatile IPackageManager sPackageManager; @@ -2190,9 +2191,19 @@ public final class ActivityThread { } } + public ContextImpl getSystemUiContext() { + synchronized (this) { + if (mSystemUiContext == null) { + mSystemUiContext = ContextImpl.createSystemUiContext(this); + } + return mSystemUiContext; + } + } + public void installSystemApplicationInfo(ApplicationInfo info, ClassLoader classLoader) { synchronized (this) { getSystemContext().installSystemApplicationInfo(info, classLoader); + getSystemUiContext().installSystemApplicationInfo(info, classLoader); // give ourselves a default profiler mProfiler = new Profiler(); @@ -5031,6 +5042,11 @@ public final class ActivityThread { if ((systemTheme.getChangingConfigurations() & configDiff) != 0) { systemTheme.rebase(); } + + final Theme systemUiTheme = getSystemUiContext().getTheme(); + if ((systemUiTheme.getChangingConfigurations() & configDiff) != 0) { + systemUiTheme.rebase(); + } } ArrayList<ComponentCallbacks2> callbacks = collectComponentCallbacks(false, config); @@ -5086,9 +5102,10 @@ public final class ActivityThread { // Trigger a regular Configuration change event, only with a different assetsSeq number // so that we actually call through to all components. + // TODO(adamlesinski): Change this to make use of ActivityManager's upcoming ability to + // store configurations per-process. Configuration newConfig = new Configuration(); - newConfig.unset(); - newConfig.assetsSeq = mConfiguration.assetsSeq + 1; + newConfig.assetsSeq = (mConfiguration != null ? mConfiguration.assetsSeq : 0) + 1; handleConfigurationChanged(newConfig, null); // Schedule all activities to reload diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java index 461f9cc35125..a6838f8bbf0a 100644 --- a/core/java/android/app/ApplicationPackageManager.java +++ b/core/java/android/app/ApplicationPackageManager.java @@ -1352,7 +1352,7 @@ public class ApplicationPackageManager extends PackageManager { public Resources getResourcesForApplication(@NonNull ApplicationInfo app) throws NameNotFoundException { if (app.packageName.equals("system")) { - return mContext.mMainThread.getSystemContext().getResources(); + return mContext.mMainThread.getSystemUiContext().getResources(); } final boolean sameUid = (app.uid == Process.myUid()); final Resources r = mContext.mMainThread.getTopLevelResources( @@ -1383,7 +1383,7 @@ public class ApplicationPackageManager extends PackageManager { "Call does not support special user #" + userId); } if ("system".equals(appPackageName)) { - return mContext.mMainThread.getSystemContext().getResources(); + return mContext.mMainThread.getSystemUiContext().getResources(); } try { ApplicationInfo ai = mPM.getApplicationInfo(appPackageName, sDefaultFlags, userId); diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index f95fa990b79e..c5e970f99c1f 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -2217,6 +2217,18 @@ class ContextImpl extends Context { return context; } + /** + * System Context to be used for UI. This Context has resources that can be themed. + */ + static ContextImpl createSystemUiContext(ActivityThread mainThread) { + LoadedApk packageInfo = new LoadedApk(mainThread); + ContextImpl context = new ContextImpl(null, mainThread, packageInfo, null, null, null, 0, + null); + context.setResources(createResources(null, packageInfo, null, Display.DEFAULT_DISPLAY, null, + packageInfo.getCompatibilityInfo())); + return context; + } + static ContextImpl createAppContext(ActivityThread mainThread, LoadedApk packageInfo) { if (packageInfo == null) throw new IllegalArgumentException("packageInfo"); ContextImpl context = new ContextImpl(null, mainThread, packageInfo, null, null, null, 0, diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java index b42df5e2e0fb..489a0f0975ae 100644 --- a/core/java/android/app/ResourcesManager.java +++ b/core/java/android/app/ResourcesManager.java @@ -984,7 +984,7 @@ public class ResourcesManager { final ResourcesKey key = mResourceImpls.keyAt(i); final WeakReference<ResourcesImpl> weakImplRef = mResourceImpls.valueAt(i); final ResourcesImpl impl = weakImplRef != null ? weakImplRef.get() : null; - if (impl != null && key.mResDir != null && key.mResDir.equals(baseCodePath)) { + if (impl != null && (key.mResDir == null || key.mResDir.equals(baseCodePath))) { updatedResourceKeys.put(impl, new ResourcesKey( key.mResDir, key.mSplitResDirs, diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index aa2adc74bc88..a585720ab895 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -4642,4 +4642,18 @@ public abstract class Context { public Handler getMainThreadHandler() { throw new RuntimeException("Not implemented. Must override in a subclass."); } + + /** + * Throws an exception if the Context is using system resources, + * which are non-runtime-overlay-themable and may show inconsistent UI. + * @hide + */ + public void assertRuntimeOverlayThemable() { + // Resources.getSystem() is a singleton and the only Resources not managed by + // ResourcesManager; therefore Resources.getSystem() is not themable. + if (getResources() == Resources.getSystem()) { + throw new IllegalArgumentException("Non-UI context used to display UI; " + + "get a UI context from ActivityThread#getSystemUiContext()"); + } + } } diff --git a/services/core/java/com/android/server/SystemService.java b/services/core/java/com/android/server/SystemService.java index 421d5a6ab964..c105b1244e74 100644 --- a/services/core/java/com/android/server/SystemService.java +++ b/services/core/java/com/android/server/SystemService.java @@ -16,6 +16,7 @@ package com.android.server; +import android.app.ActivityThread; import android.content.Context; import android.os.IBinder; import android.os.ServiceManager; @@ -104,6 +105,16 @@ public abstract class SystemService { } /** + * Get the system UI context. This context is to be used for displaying UI. It is themable, + * which means resources can be overridden at runtime. Do not use to retrieve properties that + * configure the behavior of the device that is not UX related. + */ + public final Context getUiContext() { + // This has already been set up by the time any SystemServices are created. + return ActivityThread.currentActivityThread().getSystemUiContext(); + } + + /** * Returns true if the system is running in safe mode. * TODO: we should define in which phase this becomes valid */ diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 81ba7a733225..4c747a1c5433 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -1350,7 +1350,13 @@ public class ActivityManagerService extends IActivityManager.Stub @GuardedBy("this") boolean mLaunchWarningShown = false; @GuardedBy("this") boolean mCheckedForSetup = false; - Context mContext; + final Context mContext; + + /** + * This Context is themable and meant for UI display (AlertDialogs, etc.). The theme can + * change at runtime. Use mContext for non-UI purposes. + */ + final Context mUiContext; /** * The time at which we will allow normal application switches again, @@ -1852,7 +1858,7 @@ public class ActivityManagerService extends IActivityManager.Stub } break; case SHOW_FACTORY_ERROR_UI_MSG: { Dialog d = new FactoryErrorDialog( - mContext, msg.getData().getCharSequence("msg")); + mUiContext, msg.getData().getCharSequence("msg")); d.show(); ensureBootCompleted(); } break; @@ -1863,7 +1869,7 @@ public class ActivityManagerService extends IActivityManager.Stub if (!app.waitedForDebugger) { Dialog d = new AppWaitingForDebuggerDialog( ActivityManagerService.this, - mContext, app); + mUiContext, app); app.waitDialog = d; app.waitedForDebugger = true; d.show(); @@ -1878,24 +1884,24 @@ public class ActivityManagerService extends IActivityManager.Stub } break; case SHOW_UID_ERROR_UI_MSG: { if (mShowDialogs) { - AlertDialog d = new BaseErrorDialog(mContext); + AlertDialog d = new BaseErrorDialog(mUiContext); d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR); d.setCancelable(false); - d.setTitle(mContext.getText(R.string.android_system_label)); - d.setMessage(mContext.getText(R.string.system_error_wipe_data)); - d.setButton(DialogInterface.BUTTON_POSITIVE, mContext.getText(R.string.ok), + d.setTitle(mUiContext.getText(R.string.android_system_label)); + d.setMessage(mUiContext.getText(R.string.system_error_wipe_data)); + d.setButton(DialogInterface.BUTTON_POSITIVE, mUiContext.getText(R.string.ok), obtainMessage(DISMISS_DIALOG_UI_MSG, d)); d.show(); } } break; case SHOW_FINGERPRINT_ERROR_UI_MSG: { if (mShowDialogs) { - AlertDialog d = new BaseErrorDialog(mContext); + AlertDialog d = new BaseErrorDialog(mUiContext); d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR); d.setCancelable(false); - d.setTitle(mContext.getText(R.string.android_system_label)); - d.setMessage(mContext.getText(R.string.system_error_manufacturer)); - d.setButton(DialogInterface.BUTTON_POSITIVE, mContext.getText(R.string.ok), + d.setTitle(mUiContext.getText(R.string.android_system_label)); + d.setMessage(mUiContext.getText(R.string.system_error_manufacturer)); + d.setButton(DialogInterface.BUTTON_POSITIVE, mUiContext.getText(R.string.ok), obtainMessage(DISMISS_DIALOG_UI_MSG, d)); d.show(); } @@ -1919,7 +1925,7 @@ public class ActivityManagerService extends IActivityManager.Stub if (mode == ActivityManager.COMPAT_MODE_DISABLED || mode == ActivityManager.COMPAT_MODE_ENABLED) { mCompatModeDialog = new CompatModeDialog( - ActivityManagerService.this, mContext, + ActivityManagerService.this, mUiContext, ar.info.applicationInfo); mCompatModeDialog.show(); } @@ -1939,7 +1945,7 @@ public class ActivityManagerService extends IActivityManager.Stub ar.packageName)) { // TODO(multi-display): Show dialog on appropriate display. mUnsupportedDisplaySizeDialog = new UnsupportedDisplaySizeDialog( - ActivityManagerService.this, mContext, ar.info.applicationInfo); + ActivityManagerService.this, mUiContext, ar.info.applicationInfo); mUnsupportedDisplaySizeDialog.show(); } } @@ -2731,6 +2737,7 @@ public class ActivityManagerService extends IActivityManager.Stub public ActivityManagerService(Injector injector) { mInjector = injector; mContext = mInjector.getContext(); + mUiContext = null; GL_ES_VERSION = 0; mActivityStarter = null; mAppErrors = null; @@ -2762,8 +2769,10 @@ public class ActivityManagerService extends IActivityManager.Stub LockGuard.installLock(this, LockGuard.INDEX_ACTIVITY); mInjector = new Injector(); mContext = systemContext; + mFactoryTest = FactoryTest.getMode(); mSystemThread = ActivityThread.currentActivityThread(); + mUiContext = mSystemThread.getSystemUiContext(); Slog.i(TAG, "Memory class: " + ActivityManager.staticGetMemoryClass()); @@ -2806,7 +2815,7 @@ public class ActivityManagerService extends IActivityManager.Stub mServices = new ActiveServices(this); mProviderMap = new ProviderMap(this); - mAppErrors = new AppErrors(mContext, this); + mAppErrors = new AppErrors(mUiContext, this); // TODO: Move creation of battery stats service outside of activity manager service. File dataDir = Environment.getDataDirectory(); @@ -23893,7 +23902,7 @@ public class ActivityManagerService extends IActivityManager.Stub final boolean updateFrameworkRes = packagesToUpdate.contains("android"); for (int i = mLruProcesses.size() - 1; i >= 0; i--) { final ProcessRecord app = mLruProcesses.get(i); - if (app.thread == null || app.pid == Process.myPid()) { + if (app.thread == null) { continue; } diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java index 21c131c3616f..ba72dcf23c98 100644 --- a/services/core/java/com/android/server/am/AppErrors.java +++ b/services/core/java/com/android/server/am/AppErrors.java @@ -98,6 +98,7 @@ class AppErrors { AppErrors(Context context, ActivityManagerService service) { + context.assertRuntimeOverlayThemable(); mService = service; mContext = context; } diff --git a/services/core/java/com/android/server/am/BaseErrorDialog.java b/services/core/java/com/android/server/am/BaseErrorDialog.java index 5f7f67a8a5e8..347a357aae04 100644 --- a/services/core/java/com/android/server/am/BaseErrorDialog.java +++ b/services/core/java/com/android/server/am/BaseErrorDialog.java @@ -34,6 +34,7 @@ class BaseErrorDialog extends AlertDialog { public BaseErrorDialog(Context context) { super(context, com.android.internal.R.style.Theme_Dialog_AppError); + context.assertRuntimeOverlayThemable(); getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT); getWindow().setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM, diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java index 9c4e700c87d3..a60dae7c7914 100644 --- a/services/core/java/com/android/server/power/PowerManagerService.java +++ b/services/core/java/com/android/server/power/PowerManagerService.java @@ -2671,11 +2671,11 @@ public final class PowerManagerService extends SystemService public void run() { synchronized (this) { if (haltMode == HALT_MODE_REBOOT_SAFE_MODE) { - ShutdownThread.rebootSafeMode(mContext, confirm); + ShutdownThread.rebootSafeMode(getUiContext(), confirm); } else if (haltMode == HALT_MODE_REBOOT) { - ShutdownThread.reboot(mContext, reason, confirm); + ShutdownThread.reboot(getUiContext(), reason, confirm); } else { - ShutdownThread.shutdown(mContext, reason, confirm); + ShutdownThread.shutdown(getUiContext(), reason, confirm); } } } diff --git a/services/core/java/com/android/server/power/ShutdownThread.java b/services/core/java/com/android/server/power/ShutdownThread.java index 841e2a158c4f..864e83ef1f86 100644 --- a/services/core/java/com/android/server/power/ShutdownThread.java +++ b/services/core/java/com/android/server/power/ShutdownThread.java @@ -79,7 +79,7 @@ public final class ShutdownThread extends Thread { private static final int SHUTDOWN_VIBRATE_MS = 500; // state tracking - private static Object sIsStartedGuard = new Object(); + private static final Object sIsStartedGuard = new Object(); private static boolean sIsStarted = false; private static boolean mReboot; @@ -121,7 +121,8 @@ public final class ShutdownThread extends Thread { * state etc. Must be called from a Looper thread in which its UI * is shown. * - * @param context Context used to display the shutdown progress dialog. + * @param context Context used to display the shutdown progress dialog. This must be a context + * suitable for displaying UI (aka Themable). * @param reason code to pass to android_reboot() (e.g. "userrequested"), or null. * @param confirm true if user confirmation is needed before shutting down. */ @@ -132,7 +133,11 @@ public final class ShutdownThread extends Thread { shutdownInner(context, confirm); } - static void shutdownInner(final Context context, boolean confirm) { + private static void shutdownInner(final Context context, boolean confirm) { + // ShutdownThread is called from many places, so best to verify here that the context passed + // in is themed. + context.assertRuntimeOverlayThemable(); + // ensure that only one thread is trying to power down. // any additional calls are just returned synchronized (sIsStartedGuard) { @@ -204,7 +209,8 @@ public final class ShutdownThread extends Thread { * state etc. Must be called from a Looper thread in which its UI * is shown. * - * @param context Context used to display the shutdown progress dialog. + * @param context Context used to display the shutdown progress dialog. This must be a context + * suitable for displaying UI (aka Themable). * @param reason code to pass to the kernel (e.g. "recovery"), or null. * @param confirm true if user confirmation is needed before shutting down. */ @@ -220,7 +226,8 @@ public final class ShutdownThread extends Thread { * Request a reboot into safe mode. Must be called from a Looper thread in which its UI * is shown. * - * @param context Context used to display the shutdown progress dialog. + * @param context Context used to display the shutdown progress dialog. This must be a context + * suitable for displaying UI (aka Themable). * @param confirm true if user confirmation is needed before shutting down. */ public static void rebootSafeMode(final Context context, boolean confirm) { diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java index 212bd61dbc9a..218d21826d93 100644 --- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java +++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java @@ -16,6 +16,7 @@ package com.android.server.statusbar; +import android.app.ActivityThread; import android.app.StatusBarManager; import android.content.ComponentName; import android.content.Context; @@ -61,6 +62,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub { private static final boolean SPEW = false; private final Context mContext; + private final WindowManagerService mWindowManager; private Handler mHandler = new Handler(); private NotificationDelegate mNotificationDelegate; @@ -777,10 +779,12 @@ public class StatusBarManagerService extends IStatusBarService.Stub { long identity = Binder.clearCallingIdentity(); try { mHandler.post(() -> { + // ShutdownThread displays UI, so give it a UI context. + Context uiContext = ActivityThread.currentActivityThread().getSystemUiContext(); if (safeMode) { - ShutdownThread.rebootSafeMode(mContext, false); + ShutdownThread.rebootSafeMode(uiContext, false); } else { - ShutdownThread.reboot(mContext, PowerManager.SHUTDOWN_USER_REQUESTED, false); + ShutdownThread.reboot(uiContext, PowerManager.SHUTDOWN_USER_REQUESTED, false); } }); } finally { diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 1691d1408356..f1796de2d342 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -102,6 +102,7 @@ import android.annotation.Nullable; import android.app.ActivityManager; import android.app.ActivityManager.TaskSnapshot; import android.app.ActivityManagerInternal; +import android.app.ActivityThread; import android.app.AppOpsManager; import android.app.IActivityManager; import android.content.BroadcastReceiver; @@ -3196,19 +3197,25 @@ public class WindowManagerService extends IWindowManager.Stub // Called by window manager policy. Not exposed externally. @Override public void shutdown(boolean confirm) { - ShutdownThread.shutdown(mContext, PowerManager.SHUTDOWN_USER_REQUESTED, confirm); + // Pass in the UI context, since ShutdownThread requires it (to show UI). + ShutdownThread.shutdown(ActivityThread.currentActivityThread().getSystemUiContext(), + PowerManager.SHUTDOWN_USER_REQUESTED, confirm); } // Called by window manager policy. Not exposed externally. @Override public void reboot(boolean confirm) { - ShutdownThread.reboot(mContext, PowerManager.SHUTDOWN_USER_REQUESTED, confirm); + // Pass in the UI context, since ShutdownThread requires it (to show UI). + ShutdownThread.reboot(ActivityThread.currentActivityThread().getSystemUiContext(), + PowerManager.SHUTDOWN_USER_REQUESTED, confirm); } // Called by window manager policy. Not exposed externally. @Override public void rebootSafeMode(boolean confirm) { - ShutdownThread.rebootSafeMode(mContext, confirm); + // Pass in the UI context, since ShutdownThread requires it (to show UI). + ShutdownThread.rebootSafeMode(ActivityThread.currentActivityThread().getSystemUiContext(), + confirm); } public void setCurrentProfileIds(final int[] currentProfileIds) { diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 3f197b7f3927..1312c8f55c48 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -475,6 +475,9 @@ public final class SystemServer { ActivityThread activityThread = ActivityThread.systemMain(); mSystemContext = activityThread.getSystemContext(); mSystemContext.setTheme(DEFAULT_SYSTEM_THEME); + + final Context systemUiContext = activityThread.getSystemUiContext(); + systemUiContext.setTheme(DEFAULT_SYSTEM_THEME); } /** |