Let SysUI set wake-from-idle alarms with impunity
In an always-on display environment the device may go into doze, but
SysUI will still need to update the display on an ongoing basis.
Bug 36506772
Test: manual
Change-Id: I0b20ba7c352bac7c278f659f0e29496cc342d381
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 55f32d7..983758b 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -24,6 +24,10 @@
<protected-broadcast android:name="com.android.systemui.action.PLUGIN_CHANGED" />
+ <!-- SysUI must be the one to define this permission; its name is
+ referenced by the core OS. -->
+ <permission android:name="android.permission.systemui.IDENTITY"
+ android:protectionLevel="signature" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index 21dae4f..5b0dc0f 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -31,7 +31,11 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.PermissionInfo;
import android.database.ContentObserver;
import android.net.Uri;
import android.os.Binder;
@@ -153,6 +157,20 @@
long mAllowWhileIdleMinTime;
int mNumTimeChanged;
+ // Bookkeeping about the identity of the "System UI" package, determined at runtime.
+
+ /**
+ * This permission must be defined by the canonical System UI package,
+ * with protection level "signature".
+ */
+ private static final String SYSTEM_UI_SELF_PERMISSION =
+ "android.permission.systemui.IDENTITY";
+
+ /**
+ * At boot we use SYSTEM_UI_SELF_PERMISSION to look up the definer's uid.
+ */
+ int mSystemUiUid;
+
/**
* The current set of user whitelisted apps for device idle mode, meaning these are allowed
* to freely schedule alarms.
@@ -960,6 +978,25 @@
}
}
+ // Determine SysUI's uid
+ final PackageManager packMan = getContext().getPackageManager();
+ try {
+ PermissionInfo sysUiPerm = packMan.getPermissionInfo(SYSTEM_UI_SELF_PERMISSION, 0);
+ ApplicationInfo sysUi = packMan.getApplicationInfo(sysUiPerm.packageName, 0);
+ if ((sysUi.privateFlags&ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0) {
+ mSystemUiUid = sysUi.uid;
+ } else {
+ Slog.e(TAG, "SysUI permission " + SYSTEM_UI_SELF_PERMISSION
+ + " defined by non-privileged app " + sysUi.packageName
+ + " - ignoring");
+ }
+ } catch (NameNotFoundException e) {
+ }
+
+ if (mSystemUiUid <= 0) {
+ Slog.wtf(TAG, "SysUI package not found!");
+ }
+
PowerManager pm = (PowerManager) getContext().getSystemService(Context.POWER_SERVICE);
mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*alarm*");
@@ -1328,6 +1365,7 @@
// This means we will allow these alarms to go off as normal even while idle, with no
// timing restrictions.
} else if (workSource == null && (callingUid < Process.FIRST_APPLICATION_UID
+ || callingUid == mSystemUiUid
|| Arrays.binarySearch(mDeviceIdleUserWhitelist,
UserHandle.getAppId(callingUid)) >= 0)) {
flags |= AlarmManager.FLAG_ALLOW_WHILE_IDLE_UNRESTRICTED;