Add privileged API to control keyguard secure notifications
I688e87cf09ad206f4f517a7be960c2aa01af8fc4, restricted privileged apps from silently becoming Device Admins. Ia4e1ce9b81756e7f84ed0aa22d97e0b968cd8d89 added privileged APIs for locking the device and resetting the password. We continue that work by providing an alternative for DevicePolicyManager#setKeyguardDisabledFeatures guarded by android.permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS Bug: 111153365 Bug: 112601004 Test: Secure notifications can be redacted on keyguard Change-Id: If81cecf6e74f7abcff581a122c4b68cc04ff57c6
This commit is contained in:
@@ -58,6 +58,7 @@ package android {
|
||||
field public static final java.lang.String CONNECTIVITY_USE_RESTRICTED_NETWORKS = "android.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS";
|
||||
field public static final java.lang.String CONTROL_DISPLAY_SATURATION = "android.permission.CONTROL_DISPLAY_SATURATION";
|
||||
field public static final java.lang.String CONTROL_INCALL_EXPERIENCE = "android.permission.CONTROL_INCALL_EXPERIENCE";
|
||||
field public static final java.lang.String CONTROL_KEYGUARD_SECURE_NOTIFICATIONS = "android.permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS";
|
||||
field public static final java.lang.String CONTROL_LOCATION_UPDATES = "android.permission.CONTROL_LOCATION_UPDATES";
|
||||
field public static final java.lang.String CONTROL_VPN = "android.permission.CONTROL_VPN";
|
||||
field public static final java.lang.String CRYPT_KEEPER = "android.permission.CRYPT_KEEPER";
|
||||
@@ -438,6 +439,8 @@ package android.app {
|
||||
}
|
||||
|
||||
public class KeyguardManager {
|
||||
method public void setPrivateNotificationsAllowed(boolean);
|
||||
method public boolean getPrivateNotificationsAllowed();
|
||||
method public android.content.Intent createConfirmFactoryResetCredentialIntent(java.lang.CharSequence, java.lang.CharSequence, java.lang.CharSequence);
|
||||
method public void requestDismissKeyguard(android.app.Activity, java.lang.CharSequence, android.app.KeyguardManager.KeyguardDismissCallback);
|
||||
}
|
||||
|
||||
@@ -174,4 +174,7 @@ interface INotificationManager
|
||||
void revokeNotificationDelegate(String callingPkg);
|
||||
String getNotificationDelegate(String callingPkg);
|
||||
boolean canNotifyAsPackage(String callingPkg, String targetPkg);
|
||||
|
||||
void setPrivateNotificationsAllowed(boolean allow);
|
||||
boolean getPrivateNotificationsAllowed();
|
||||
}
|
||||
|
||||
@@ -62,6 +62,7 @@ public class KeyguardManager {
|
||||
private final IWindowManager mWM;
|
||||
private final IActivityManager mAm;
|
||||
private final ITrustManager mTrustManager;
|
||||
private final INotificationManager mNotificationManager;
|
||||
|
||||
/**
|
||||
* Intent used to prompt user for device credentials.
|
||||
@@ -219,6 +220,45 @@ public class KeyguardManager {
|
||||
return intent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Controls whether notifications can be shown atop a securely locked screen in their full
|
||||
* private form (same as when the device is unlocked).
|
||||
*
|
||||
* <p>Other sources like the DevicePolicyManger and Settings app can modify this configuration.
|
||||
* The result is that private notifications are only shown if all sources allow it.
|
||||
*
|
||||
* @param allow secure notifications can be shown if {@code true},
|
||||
* secure notifications cannot be shown if {@code false}
|
||||
* @hide
|
||||
*/
|
||||
@RequiresPermission(Manifest.permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS)
|
||||
@SystemApi
|
||||
public void setPrivateNotificationsAllowed(boolean allow) {
|
||||
try {
|
||||
mNotificationManager.setPrivateNotificationsAllowed(allow);
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether notifications can be shown atop a securely locked screen in their full
|
||||
* private form (same as when the device is unlocked).
|
||||
*
|
||||
* @return {@code true} if secure notifications can be shown, {@code false} otherwise.
|
||||
* By default, private notifications are allowed.
|
||||
* @hide
|
||||
*/
|
||||
@RequiresPermission(Manifest.permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS)
|
||||
@SystemApi
|
||||
public boolean getPrivateNotificationsAllowed() {
|
||||
try {
|
||||
return mNotificationManager.getPrivateNotificationsAllowed();
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
private String getSettingsPackageForIntent(Intent intent) {
|
||||
List<ResolveInfo> resolveInfos = mContext.getPackageManager()
|
||||
.queryIntentActivities(intent, PackageManager.MATCH_SYSTEM_ONLY);
|
||||
@@ -335,6 +375,8 @@ public class KeyguardManager {
|
||||
mAm = ActivityManager.getService();
|
||||
mTrustManager = ITrustManager.Stub.asInterface(
|
||||
ServiceManager.getServiceOrThrow(Context.TRUST_SERVICE));
|
||||
mNotificationManager = INotificationManager.Stub.asInterface(
|
||||
ServiceManager.getServiceOrThrow(Context.NOTIFICATION_SERVICE));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -3851,6 +3851,11 @@
|
||||
<permission android:name="android.permission.CONTROL_KEYGUARD"
|
||||
android:protectionLevel="signature" />
|
||||
|
||||
<!-- @SystemApi Allows an application to control keyguard features like secure notifications.
|
||||
@hide -->
|
||||
<permission android:name="android.permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS"
|
||||
android:protectionLevel="signature|privileged" />
|
||||
|
||||
<!-- Allows an application to listen to trust changes. Only allowed for system processes.
|
||||
@hide -->
|
||||
<permission android:name="android.permission.TRUST_LISTENER"
|
||||
|
||||
@@ -374,6 +374,7 @@ applications that come with the platform
|
||||
<permission name="android.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST"/>
|
||||
<permission name="android.permission.CHANGE_OVERLAY_PACKAGES"/>
|
||||
<permission name="android.permission.CONNECTIVITY_INTERNAL"/>
|
||||
<permission name="android.permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS"/>
|
||||
<permission name="android.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS"/>
|
||||
<permission name="android.permission.CONTROL_VPN"/>
|
||||
<permission name="android.permission.DUMP"/>
|
||||
|
||||
@@ -125,6 +125,7 @@
|
||||
<uses-permission android:name="android.permission.USE_FINGERPRINT" />
|
||||
<uses-permission android:name="android.permission.RESET_FINGERPRINT_LOCKOUT" />
|
||||
<uses-permission android:name="android.permission.MANAGE_SLICE_PERMISSIONS" />
|
||||
<uses-permission android:name="android.permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS" />
|
||||
|
||||
<!-- Needed for WallpaperManager.clear in ImageWallpaper.updateWallpaperLocked -->
|
||||
<uses-permission android:name="android.permission.SET_WALLPAPER"/>
|
||||
|
||||
@@ -397,7 +397,8 @@ public class NotificationLockscreenUserManagerImpl implements
|
||||
Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 0, userHandle);
|
||||
final boolean allowedByDpm = adminAllowsKeyguardFeature(userHandle,
|
||||
DevicePolicyManager.KEYGUARD_DISABLE_SECURE_NOTIFICATIONS);
|
||||
final boolean allowed = allowedByUser && allowedByDpm;
|
||||
final boolean allowedBySystem = mKeyguardManager.getPrivateNotificationsAllowed();
|
||||
final boolean allowed = allowedByUser && allowedByDpm && allowedBySystem;
|
||||
mUsersAllowingNotifications.append(userHandle, allowed);
|
||||
return allowed;
|
||||
}
|
||||
|
||||
@@ -86,6 +86,7 @@ import static com.android.server.utils.PriorityDump.PRIORITY_ARG_CRITICAL;
|
||||
import static com.android.server.utils.PriorityDump.PRIORITY_ARG_NORMAL;
|
||||
|
||||
import android.Manifest;
|
||||
import android.Manifest.permission;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.app.ActivityManager;
|
||||
@@ -398,6 +399,10 @@ public class NotificationManagerService extends SystemService {
|
||||
private static final String TAG_NOTIFICATION_POLICY = "notification-policy";
|
||||
private static final String ATTR_VERSION = "version";
|
||||
|
||||
private static final String LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_TAG =
|
||||
"allow-secure-notifications-on-lockscreen";
|
||||
private static final String LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_VALUE = "value";
|
||||
|
||||
private RankingHelper mRankingHelper;
|
||||
private PreferencesHelper mPreferencesHelper;
|
||||
|
||||
@@ -406,6 +411,7 @@ public class NotificationManagerService extends SystemService {
|
||||
private NotificationAssistants mAssistants;
|
||||
private ConditionProviders mConditionProviders;
|
||||
private NotificationUsageStats mUsageStats;
|
||||
private boolean mLockScreenAllowSecureNotifications;
|
||||
|
||||
private static final int MY_UID = Process.myUid();
|
||||
private static final int MY_PID = Process.myPid();
|
||||
@@ -552,6 +558,11 @@ public class NotificationManagerService extends SystemService {
|
||||
mConditionProviders.readXml(parser, mAllowedManagedServicePackages);
|
||||
migratedManagedServices = true;
|
||||
}
|
||||
if (LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_TAG.equals(parser.getName())) {
|
||||
mLockScreenAllowSecureNotifications =
|
||||
safeBoolean(parser.getAttributeValue(null,
|
||||
LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_VALUE), true);
|
||||
}
|
||||
}
|
||||
|
||||
if (!migratedManagedServices) {
|
||||
@@ -626,6 +637,7 @@ public class NotificationManagerService extends SystemService {
|
||||
mListeners.writeXml(out, forBackup);
|
||||
mAssistants.writeXml(out, forBackup);
|
||||
mConditionProviders.writeXml(out, forBackup);
|
||||
writeSecureNotificationsPolicy(out);
|
||||
out.endTag(null, TAG_NOTIFICATION_POLICY);
|
||||
out.endDocument();
|
||||
}
|
||||
@@ -3693,6 +3705,31 @@ public class NotificationManagerService extends SystemService {
|
||||
return new ParceledListSlice<>(groups);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPrivateNotificationsAllowed(boolean allow) {
|
||||
if (PackageManager.PERMISSION_GRANTED
|
||||
!= getContext().checkCallingPermission(
|
||||
permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS)) {
|
||||
throw new SecurityException(
|
||||
"Requires CONTROL_KEYGUARD_SECURE_NOTIFICATIONS permission");
|
||||
}
|
||||
if (allow != mLockScreenAllowSecureNotifications) {
|
||||
mLockScreenAllowSecureNotifications = allow;
|
||||
savePolicyFile();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getPrivateNotificationsAllowed() {
|
||||
if (PackageManager.PERMISSION_GRANTED
|
||||
!= getContext().checkCallingPermission(
|
||||
permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS)) {
|
||||
throw new SecurityException(
|
||||
"Requires CONTROL_KEYGUARD_SECURE_NOTIFICATIONS permission");
|
||||
}
|
||||
return mLockScreenAllowSecureNotifications;
|
||||
}
|
||||
|
||||
private void verifyPrivilegedListener(INotificationListener token, UserHandle user,
|
||||
boolean assistantAllowed) {
|
||||
ManagedServiceInfo info;
|
||||
@@ -7562,4 +7599,16 @@ public class NotificationManagerService extends SystemService {
|
||||
getOutPrintWriter().println(USAGE);
|
||||
}
|
||||
}
|
||||
|
||||
private void writeSecureNotificationsPolicy(XmlSerializer out) throws IOException {
|
||||
out.startTag(null, LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_TAG);
|
||||
out.attribute(null, LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_VALUE,
|
||||
Boolean.toString(mLockScreenAllowSecureNotifications));
|
||||
out.endTag(null, LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_TAG);
|
||||
}
|
||||
|
||||
private static boolean safeBoolean(String val, boolean defValue) {
|
||||
if (TextUtils.isEmpty(val)) return defValue;
|
||||
return Boolean.parseBoolean(val);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user