Merge "Revert "Prevent exfiltration of system files via user image settings."" into sc-dev
diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
index 9572808..d1e3481 100644
--- a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
@@ -104,6 +104,7 @@
import android.text.format.DateFormat;
import android.util.ArrayMap;
import android.util.ArraySet;
+import android.util.EventLog;
import android.util.IndentingPrintWriter;
import android.util.Log;
import android.util.LongArrayQueue;
@@ -2031,7 +2032,11 @@
+ " reached for uid: " + UserHandle.formatUid(callingUid)
+ ", callingPackage: " + callingPackage;
Slog.w(TAG, errorMsg);
- throw new IllegalStateException(errorMsg);
+ if (callingUid != Process.SYSTEM_UID) {
+ throw new IllegalStateException(errorMsg);
+ } else {
+ EventLog.writeEvent(0x534e4554, "234441463", -1, errorMsg);
+ }
}
setImplLocked(type, triggerAtTime, triggerElapsed, windowLength, interval, operation,
directReceiver, listenerTag, flags, workSource, alarmClock, callingUid,
diff --git a/core/java/android/accounts/Account.java b/core/java/android/accounts/Account.java
index e6cdcc0..0d6a079 100644
--- a/core/java/android/accounts/Account.java
+++ b/core/java/android/accounts/Account.java
@@ -31,7 +31,6 @@
import com.android.internal.annotations.GuardedBy;
-import java.util.Objects;
import java.util.Set;
/**
@@ -87,12 +86,6 @@
if (TextUtils.isEmpty(type)) {
throw new IllegalArgumentException("the type must not be empty: " + type);
}
- if (name.length() > 200) {
- throw new IllegalArgumentException("account name is longer than 200 characters");
- }
- if (type.length() > 200) {
- throw new IllegalArgumentException("account type is longer than 200 characters");
- }
this.name = name;
this.type = type;
this.accessId = accessId;
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 4376d22..644a87d 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -4282,8 +4282,8 @@
try {
getService().broadcastIntentWithFeature(
null, null, intent, null, null, Activity.RESULT_OK, null, null,
- null /*requiredPermissions*/, null /*excludedPermissions*/, appOp, null, false,
- true, userId);
+ null /*requiredPermissions*/, null /*excludedPermissions*/,
+ null /*excludedPackages*/, appOp, null, false, true, userId);
} catch (RemoteException ex) {
}
}
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index d932a29..fc89e13 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -2463,8 +2463,8 @@
* restriction} for a certain app-op.
*/
private static RestrictionBypass[] sOpAllowSystemRestrictionBypass = new RestrictionBypass[] {
- new RestrictionBypass(true, false), //COARSE_LOCATION
- new RestrictionBypass(true, false), //FINE_LOCATION
+ new RestrictionBypass(true, false, false), //COARSE_LOCATION
+ new RestrictionBypass(true, false, false), //FINE_LOCATION
null, //GPS
null, //VIBRATE
null, //READ_CONTACTS
@@ -2473,7 +2473,7 @@
null, //WRITE_CALL_LOG
null, //READ_CALENDAR
null, //WRITE_CALENDAR
- new RestrictionBypass(true, false), //WIFI_SCAN
+ new RestrictionBypass(false, true, false), //WIFI_SCAN
null, //POST_NOTIFICATION
null, //NEIGHBORING_CELLS
null, //CALL_PHONE
@@ -2487,10 +2487,10 @@
null, //READ_ICC_SMS
null, //WRITE_ICC_SMS
null, //WRITE_SETTINGS
- new RestrictionBypass(true, false), //SYSTEM_ALERT_WINDOW
+ new RestrictionBypass(false, true, false), //SYSTEM_ALERT_WINDOW
null, //ACCESS_NOTIFICATIONS
null, //CAMERA
- new RestrictionBypass(false, true), //RECORD_AUDIO
+ new RestrictionBypass(false, false, true), //RECORD_AUDIO
null, //PLAY_AUDIO
null, //READ_CLIPBOARD
null, //WRITE_CLIPBOARD
@@ -2508,7 +2508,7 @@
null, //MONITOR_HIGH_POWER_LOCATION
null, //GET_USAGE_STATS
null, //MUTE_MICROPHONE
- new RestrictionBypass(true, false), //TOAST_WINDOW
+ new RestrictionBypass(false, true, false), //TOAST_WINDOW
null, //PROJECT_MEDIA
null, //ACTIVATE_VPN
null, //WALLPAPER
@@ -2540,7 +2540,7 @@
null, // ACCEPT_HANDOVER
null, // MANAGE_IPSEC_HANDOVERS
null, // START_FOREGROUND
- new RestrictionBypass(true, false), // BLUETOOTH_SCAN
+ new RestrictionBypass(false, true, false), // BLUETOOTH_SCAN
null, // USE_BIOMETRIC
null, // ACTIVITY_RECOGNITION
null, // SMS_FINANCIAL_TRANSACTIONS
@@ -3105,6 +3105,9 @@
* @hide
*/
public static class RestrictionBypass {
+ /** Does the app need to be system uid to bypass the restriction */
+ public boolean isSystemUid;
+
/** Does the app need to be privileged to bypass the restriction */
public boolean isPrivileged;
@@ -3114,12 +3117,14 @@
*/
public boolean isRecordAudioRestrictionExcept;
- public RestrictionBypass(boolean isPrivileged, boolean isRecordAudioRestrictionExcept) {
+ public RestrictionBypass(boolean isSystemUid, boolean isPrivileged,
+ boolean isRecordAudioRestrictionExcept) {
+ this.isSystemUid = isSystemUid;
this.isPrivileged = isPrivileged;
this.isRecordAudioRestrictionExcept = isRecordAudioRestrictionExcept;
}
- public static RestrictionBypass UNRESTRICTED = new RestrictionBypass(true, true);
+ public static RestrictionBypass UNRESTRICTED = new RestrictionBypass(false, true, true);
}
/**
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 4db1f71..02adaef 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -1177,7 +1177,7 @@
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
null, Activity.RESULT_OK, null, null, null, null /*excludedPermissions=*/,
- AppOpsManager.OP_NONE, null, false, false, getUserId());
+ null, AppOpsManager.OP_NONE, null, false, false, getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1194,7 +1194,7 @@
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
null, Activity.RESULT_OK, null, null, receiverPermissions,
- null /*excludedPermissions=*/, AppOpsManager.OP_NONE, null, false, false,
+ null /*excludedPermissions=*/, null, AppOpsManager.OP_NONE, null, false, false,
getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -1210,7 +1210,7 @@
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
null, Activity.RESULT_OK, null, null, receiverPermissions,
- null /*excludedPermissions=*/, AppOpsManager.OP_NONE, null, false, false,
+ null /*excludedPermissions=*/, null, AppOpsManager.OP_NONE, null, false, false,
getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -1227,8 +1227,8 @@
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
null, Activity.RESULT_OK, null, null, receiverPermissions,
- null /*excludedPermissions=*/, AppOpsManager.OP_NONE, options, false, false,
- getUserId());
+ null /*excludedPermissions=*/, null /*excludedPackages*/,
+ AppOpsManager.OP_NONE, options, false, false, getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1243,7 +1243,7 @@
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
null, Activity.RESULT_OK, null, null, receiverPermissions,
- null /*excludedPermissions=*/, AppOpsManager.OP_NONE, null, false, false,
+ null /*excludedPermissions=*/, null, AppOpsManager.OP_NONE, null, false, false,
user.getIdentifier());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -1252,7 +1252,7 @@
@Override
public void sendBroadcastMultiplePermissions(Intent intent, String[] receiverPermissions,
- String[] excludedPermissions) {
+ String[] excludedPermissions, String[] excludedPackages) {
warnIfCallingFromSystemProcess();
String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
try {
@@ -1260,7 +1260,7 @@
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
null, Activity.RESULT_OK, null, null, receiverPermissions, excludedPermissions,
- AppOpsManager.OP_NONE, null, false, false, getUserId());
+ excludedPackages, AppOpsManager.OP_NONE, null, false, false, getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1277,8 +1277,8 @@
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
null, Activity.RESULT_OK, null, null, receiverPermissions,
- null /*excludedPermissions=*/, AppOpsManager.OP_NONE, options, false, false,
- getUserId());
+ null /*excludedPermissions=*/, null, AppOpsManager.OP_NONE, options, false,
+ false, getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1295,7 +1295,7 @@
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
null, Activity.RESULT_OK, null, null, receiverPermissions,
- null /*excludedPermissions=*/, appOp, null, false, false, getUserId());
+ null /*excludedPermissions=*/, null, appOp, null, false, false, getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1312,7 +1312,7 @@
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
null, Activity.RESULT_OK, null, null, receiverPermissions,
- null /*excludedPermissions=*/, AppOpsManager.OP_NONE, null, true, false,
+ null /*excludedPermissions=*/, null, AppOpsManager.OP_NONE, null, true, false,
getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -1376,7 +1376,7 @@
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
rd, initialCode, initialData, initialExtras, receiverPermissions,
- null /*excludedPermissions=*/, appOp, options, true, false, getUserId());
+ null /*excludedPermissions=*/, null, appOp, options, true, false, getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1390,7 +1390,7 @@
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
null, Activity.RESULT_OK, null, null, null, null /*excludedPermissions=*/,
- AppOpsManager.OP_NONE, null, false, false, user.getIdentifier());
+ null, AppOpsManager.OP_NONE, null, false, false, user.getIdentifier());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1413,8 +1413,8 @@
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
null, Activity.RESULT_OK, null, null, receiverPermissions,
- null /*excludedPermissions=*/, AppOpsManager.OP_NONE, options, false, false,
- user.getIdentifier());
+ null /*excludedPermissions=*/, null, AppOpsManager.OP_NONE, options, false,
+ false, user.getIdentifier());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1431,7 +1431,8 @@
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
null, Activity.RESULT_OK, null, null, receiverPermissions,
- null /*excludedPermissions=*/, appOp, null, false, false, user.getIdentifier());
+ null /*excludedPermissions=*/, null, appOp, null, false, false,
+ user.getIdentifier());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1482,7 +1483,7 @@
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
rd, initialCode, initialData, initialExtras, receiverPermissions,
- null /*excludedPermissions=*/, appOp, options, true, false,
+ null /*excludedPermissions=*/, null, appOp, options, true, false,
user.getIdentifier());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -1524,7 +1525,7 @@
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
null, Activity.RESULT_OK, null, null, null, null /*excludedPermissions=*/,
- AppOpsManager.OP_NONE, null, false, true, getUserId());
+ null, AppOpsManager.OP_NONE, null, false, true, getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1563,7 +1564,7 @@
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
null, Activity.RESULT_OK, null, null, null, null /*excludedPermissions=*/,
- AppOpsManager.OP_NONE, options, false, true, getUserId());
+ null, AppOpsManager.OP_NONE, options, false, true, getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1599,7 +1600,7 @@
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
rd, initialCode, initialData, initialExtras, null,
- null /*excludedPermissions=*/, AppOpsManager.OP_NONE, null, true, true,
+ null /*excludedPermissions=*/, null, AppOpsManager.OP_NONE, null, true, true,
getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -1632,7 +1633,7 @@
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
null, Activity.RESULT_OK, null, null, null, null /*excludedPermissions=*/,
- AppOpsManager.OP_NONE, null, false, true, user.getIdentifier());
+ null, AppOpsManager.OP_NONE, null, false, true, user.getIdentifier());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1647,7 +1648,7 @@
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
null, Activity.RESULT_OK, null, null, null, null /*excludedPermissions=*/,
- AppOpsManager.OP_NONE, options, false, true, user.getIdentifier());
+ null, AppOpsManager.OP_NONE, options, false, true, user.getIdentifier());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1682,7 +1683,7 @@
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
rd, initialCode, initialData, initialExtras, null,
- null /*excludedPermissions=*/, AppOpsManager.OP_NONE, null, true, true,
+ null /*excludedPermissions=*/, null, AppOpsManager.OP_NONE, null, true, true,
user.getIdentifier());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index b90b9a1..b74ed3a 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -138,7 +138,7 @@
int broadcastIntentWithFeature(in IApplicationThread caller, in String callingFeatureId,
in Intent intent, in String resolvedType, in IIntentReceiver resultTo, int resultCode,
in String resultData, in Bundle map, in String[] requiredPermissions, in String[] excludePermissions,
- int appOp, in Bundle options, boolean serialized, boolean sticky, int userId);
+ in String[] excludePackages, int appOp, in Bundle options, boolean serialized, boolean sticky, int userId);
void unbroadcastIntent(in IApplicationThread caller, in Intent intent, int userId);
@UnsupportedAppUsage
oneway void finishReceiver(in IBinder who, int resultCode, in String resultData, in Bundle map,
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 0e04ad3..cbe81ea 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -19,6 +19,7 @@
import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
import android.Manifest.permission;
+import android.accounts.Account;
import android.annotation.CallbackExecutor;
import android.annotation.ColorInt;
import android.annotation.IntDef;
@@ -165,6 +166,27 @@
this(context, service, false);
}
+ /**
+ * Called when a managed profile has been provisioned.
+ *
+ * @throws SecurityException if the caller does not hold
+ * {@link android.Manifest.permission#MANAGE_PROFILE_AND_DEVICE_OWNERS}.
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS)
+ public void finalizeWorkProfileProvisioning(
+ @NonNull UserHandle managedProfileUser, @Nullable Account migratedAccount) {
+ Objects.requireNonNull(managedProfileUser, "managedProfileUser can't be null");
+ if (mService == null) {
+ throw new IllegalStateException("Could not find DevicePolicyManagerService");
+ }
+ try {
+ mService.finalizeWorkProfileProvisioning(managedProfileUser, migratedAccount);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
/** @hide */
@VisibleForTesting
protected DevicePolicyManager(Context context, IDevicePolicyManager service,
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index b6c48a1..61c31fe 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -17,6 +17,7 @@
package android.app.admin;
+import android.accounts.Account;
import android.app.admin.NetworkEvent;
import android.app.IApplicationThread;
import android.app.IServiceConnection;
@@ -97,6 +98,8 @@
int getCurrentFailedPasswordAttempts(int userHandle, boolean parent);
int getProfileWithMinimumFailedPasswordsForWipe(int userHandle, boolean parent);
+ void finalizeWorkProfileProvisioning(in UserHandle managedProfileUser, in Account migratedAccount);
+
void setMaximumFailedPasswordsForWipe(in ComponentName admin, int num, boolean parent);
int getMaximumFailedPasswordsForWipe(in ComponentName admin, int userHandle, boolean parent);
diff --git a/core/java/android/content/AbstractThreadedSyncAdapter.java b/core/java/android/content/AbstractThreadedSyncAdapter.java
index a086a30..da4ecdd 100644
--- a/core/java/android/content/AbstractThreadedSyncAdapter.java
+++ b/core/java/android/content/AbstractThreadedSyncAdapter.java
@@ -21,6 +21,7 @@
import android.accounts.Account;
import android.annotation.MainThread;
import android.annotation.NonNull;
+import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
@@ -171,8 +172,20 @@
}
private class ISyncAdapterImpl extends ISyncAdapter.Stub {
+ private boolean isCallerSystem() {
+ final long callingUid = Binder.getCallingUid();
+ if (callingUid != Process.SYSTEM_UID) {
+ android.util.EventLog.writeEvent(0x534e4554, "203229608", -1, "");
+ return false;
+ }
+ return true;
+ }
+
@Override
public void onUnsyncableAccount(ISyncAdapterUnsyncableAccountCallback cb) {
+ if (!isCallerSystem()) {
+ return;
+ }
Handler.getMain().sendMessage(obtainMessage(
AbstractThreadedSyncAdapter::handleOnUnsyncableAccount,
AbstractThreadedSyncAdapter.this, cb));
@@ -181,12 +194,16 @@
@Override
public void startSync(ISyncContext syncContext, String authority, Account account,
Bundle extras) {
+ if (!isCallerSystem()) {
+ return;
+ }
if (ENABLE_LOG) {
if (extras != null) {
extras.size(); // Unparcel so its toString() will show the contents.
}
Log.d(TAG, "startSync() start " + authority + " " + account + " " + extras);
}
+
try {
final SyncContext syncContextClient = new SyncContext(syncContext);
@@ -242,6 +259,9 @@
@Override
public void cancelSync(ISyncContext syncContext) {
+ if (!isCallerSystem()) {
+ return;
+ }
try {
// synchronize to make sure that mSyncThreads doesn't change between when we
// check it and when we use it
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 08e95a2..9d9cc470 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -2212,6 +2212,19 @@
*/
public void sendBroadcastMultiplePermissions(@NonNull Intent intent,
@NonNull String[] receiverPermissions, @Nullable String[] excludedPermissions) {
+ sendBroadcastMultiplePermissions(intent, receiverPermissions, excludedPermissions, null);
+ }
+
+
+ /**
+ * Like {@link #sendBroadcastMultiplePermissions(Intent, String[], String[])}, but also allows
+ * specification of a list of excluded packages.
+ *
+ * @hide
+ */
+ public void sendBroadcastMultiplePermissions(@NonNull Intent intent,
+ @NonNull String[] receiverPermissions, @Nullable String[] excludedPermissions,
+ @Nullable String[] excludedPackages) {
throw new RuntimeException("Not implemented. Must override in a subclass.");
}
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index 6324d0e..985293c 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -494,8 +494,10 @@
/** @hide */
@Override
public void sendBroadcastMultiplePermissions(@NonNull Intent intent,
- @NonNull String[] receiverPermissions, @Nullable String[] excludedPermissions) {
- mBase.sendBroadcastMultiplePermissions(intent, receiverPermissions, excludedPermissions);
+ @NonNull String[] receiverPermissions, @Nullable String[] excludedPermissions,
+ @Nullable String[] excludedPackages) {
+ mBase.sendBroadcastMultiplePermissions(intent, receiverPermissions, excludedPermissions,
+ excludedPackages);
}
/** @hide */
diff --git a/core/java/android/content/pm/IPackageInstallerSession.aidl b/core/java/android/content/pm/IPackageInstallerSession.aidl
index f72288c..9a7a949 100644
--- a/core/java/android/content/pm/IPackageInstallerSession.aidl
+++ b/core/java/android/content/pm/IPackageInstallerSession.aidl
@@ -55,4 +55,5 @@
int getParentSessionId();
boolean isStaged();
+ int getInstallFlags();
}
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index 3f8aedb..4030708 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -1432,6 +1432,18 @@
}
/**
+ * @return Session's {@link SessionParams#installFlags}.
+ * @hide
+ */
+ public int getInstallFlags() {
+ try {
+ return mSession.getInstallFlags();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* @return the session ID of the multi-package session that this belongs to or
* {@link SessionInfo#INVALID_ID} if it does not belong to a multi-package session.
*/
diff --git a/core/java/android/content/pm/parsing/ParsingPackageUtils.java b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
index dce242c..b785d35 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageUtils.java
+++ b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
@@ -20,6 +20,7 @@
import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST;
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
+import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_ONLY_COREAPP_ALLOWED;
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_RESOURCES_ARSC_COMPRESSED;
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION;
@@ -905,6 +906,13 @@
);
}
+ if (ParsedPermissionUtils.declareDuplicatePermission(pkg)) {
+ return input.error(
+ INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+ "Declare duplicate permissions with different protection levels or group."
+ );
+ }
+
convertNewPermissions(pkg);
convertSplitPermissions(pkg);
diff --git a/core/java/android/content/pm/parsing/component/ParsedPermissionUtils.java b/core/java/android/content/pm/parsing/component/ParsedPermissionUtils.java
index 8afa70e..9b46594 100644
--- a/core/java/android/content/pm/parsing/component/ParsedPermissionUtils.java
+++ b/core/java/android/content/pm/parsing/component/ParsedPermissionUtils.java
@@ -25,6 +25,8 @@
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
+import android.util.ArrayMap;
+import android.util.EventLog;
import android.util.Slog;
import com.android.internal.R;
@@ -32,6 +34,8 @@
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
+import java.util.List;
+import java.util.Objects;
/** @hide */
public class ParsedPermissionUtils {
@@ -233,4 +237,49 @@
return ComponentParseUtils.parseAllMetaData(pkg, res, parser, tag, permissionGroup,
input);
}
+
+ /**
+ * Determines if a duplicate permission is malformed .i.e. defines different protection level
+ * or group
+ */
+ private static boolean isMalformedDuplicate(ParsedPermission p1, ParsedPermission p2) {
+ // Since a permission tree is also added as a permission with normal protection
+ // level, we need to skip if the parsedPermission is a permission tree.
+ if (p1 == null || p2 == null || p1.isTree() || p2.isTree()) {
+ return false;
+ }
+
+ if (p1.getProtectionLevel() != p2.getProtectionLevel()) {
+ return true;
+ }
+ if (!Objects.equals(p1.getGroup(), p2.getGroup())) {
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * @return {@code true} if the package declares malformed duplicate permissions.
+ *
+ */
+ public static boolean declareDuplicatePermission(@NonNull ParsingPackage pkg) {
+ final List<ParsedPermission> permissions = pkg.getPermissions();
+ final int size = permissions.size();
+ if (size > 0) {
+ final ArrayMap<String, ParsedPermission> checkDuplicatePerm = new ArrayMap<>(size);
+ for (int i = 0; i < size; i++) {
+ final ParsedPermission parsedPermission = permissions.get(i);
+ final String name = parsedPermission.getName();
+ final ParsedPermission perm = checkDuplicatePerm.get(name);
+ if (isMalformedDuplicate(parsedPermission, perm)) {
+ // Fix for b/213323615
+ EventLog.writeEvent(0x534e4554, "213323615");
+ return true;
+ }
+ checkDuplicatePerm.put(name, parsedPermission);
+ }
+ }
+ return false;
+ }
}
diff --git a/core/java/android/hardware/biometrics/BiometricPrompt.java b/core/java/android/hardware/biometrics/BiometricPrompt.java
index 3f3db29..35c3667 100644
--- a/core/java/android/hardware/biometrics/BiometricPrompt.java
+++ b/core/java/android/hardware/biometrics/BiometricPrompt.java
@@ -408,6 +408,31 @@
}
/**
+ * Flag to decide if authentication should ignore enrollment state.
+ * Defaults to false (not ignoring enrollment state)
+ * @param ignoreEnrollmentState
+ * @return This builder.
+ * @hide
+ */
+ @NonNull
+ public Builder setIgnoreEnrollmentState(boolean ignoreEnrollmentState) {
+ mPromptInfo.setIgnoreEnrollmentState(ignoreEnrollmentState);
+ return this;
+ }
+
+ /**
+ * Set if BiometricPrompt is being used by the legacy fingerprint manager API.
+ * @param sensorId sensor id
+ * @return This builder.
+ * @hide
+ */
+ @NonNull
+ public Builder setIsForLegacyFingerprintManager(int sensorId) {
+ mPromptInfo.setIsForLegacyFingerprintManager(sensorId);
+ return this;
+ }
+
+ /**
* Creates a {@link BiometricPrompt}.
*
* @return An instance of {@link BiometricPrompt}.
@@ -841,26 +866,34 @@
@NonNull @CallbackExecutor Executor executor,
@NonNull AuthenticationCallback callback,
int userId) {
- authenticateUserForOperation(cancel, executor, callback, userId, 0 /* operationId */);
+ if (cancel == null) {
+ throw new IllegalArgumentException("Must supply a cancellation signal");
+ }
+ if (executor == null) {
+ throw new IllegalArgumentException("Must supply an executor");
+ }
+ if (callback == null) {
+ throw new IllegalArgumentException("Must supply a callback");
+ }
+
+ authenticateInternal(0 /* operationId */, cancel, executor, callback, userId);
}
/**
- * Authenticates for the given user and keystore operation.
+ * Authenticates for the given keystore operation.
*
* @param cancel An object that can be used to cancel authentication
* @param executor An executor to handle callback events
* @param callback An object to receive authentication events
- * @param userId The user to authenticate
* @param operationId The keystore operation associated with authentication
*
* @hide
*/
- @RequiresPermission(USE_BIOMETRIC_INTERNAL)
- public void authenticateUserForOperation(
+ @RequiresPermission(USE_BIOMETRIC)
+ public void authenticateForOperation(
@NonNull CancellationSignal cancel,
@NonNull @CallbackExecutor Executor executor,
@NonNull AuthenticationCallback callback,
- int userId,
long operationId) {
if (cancel == null) {
throw new IllegalArgumentException("Must supply a cancellation signal");
@@ -871,7 +904,8 @@
if (callback == null) {
throw new IllegalArgumentException("Must supply a callback");
}
- authenticateInternal(operationId, cancel, executor, callback, userId);
+
+ authenticateInternal(operationId, cancel, executor, callback, mContext.getUserId());
}
/**
@@ -1005,7 +1039,7 @@
private void cancelAuthentication() {
if (mService != null) {
try {
- mService.cancelAuthentication(mToken, mContext.getOpPackageName());
+ mService.cancelAuthentication(mToken, mContext.getPackageName());
} catch (RemoteException e) {
Log.e(TAG, "Unable to cancel authentication", e);
}
@@ -1065,9 +1099,8 @@
promptInfo = mPromptInfo;
}
- mService.authenticate(mToken, operationId, userId, mBiometricServiceReceiver,
- mContext.getOpPackageName(), promptInfo);
-
+ mService.authenticate(mToken, operationId, userId,
+ mBiometricServiceReceiver, mContext.getPackageName(), promptInfo);
} catch (RemoteException e) {
Log.e(TAG, "Remote exception while authenticating", e);
mExecutor.execute(() -> callback.onAuthenticationError(
diff --git a/core/java/android/hardware/biometrics/ITestSessionCallback.aidl b/core/java/android/hardware/biometrics/ITestSessionCallback.aidl
index 3d9517f..b336a9f 100644
--- a/core/java/android/hardware/biometrics/ITestSessionCallback.aidl
+++ b/core/java/android/hardware/biometrics/ITestSessionCallback.aidl
@@ -19,7 +19,7 @@
* ITestSession callback for FingerprintManager and BiometricManager.
* @hide
*/
-interface ITestSessionCallback {
+oneway interface ITestSessionCallback {
void onCleanupStarted(int userId);
void onCleanupFinished(int userId);
}
diff --git a/core/java/android/hardware/biometrics/PromptInfo.java b/core/java/android/hardware/biometrics/PromptInfo.java
index 339c654..2742f0e 100644
--- a/core/java/android/hardware/biometrics/PromptInfo.java
+++ b/core/java/android/hardware/biometrics/PromptInfo.java
@@ -45,6 +45,8 @@
private boolean mReceiveSystemEvents;
@NonNull private List<Integer> mAllowedSensorIds = new ArrayList<>();
private boolean mAllowBackgroundAuthentication;
+ private boolean mIgnoreEnrollmentState;
+ private boolean mIsForLegacyFingerprintManager = false;
public PromptInfo() {
@@ -66,6 +68,8 @@
mReceiveSystemEvents = in.readBoolean();
mAllowedSensorIds = in.readArrayList(Integer.class.getClassLoader());
mAllowBackgroundAuthentication = in.readBoolean();
+ mIgnoreEnrollmentState = in.readBoolean();
+ mIsForLegacyFingerprintManager = in.readBoolean();
}
public static final Creator<PromptInfo> CREATOR = new Creator<PromptInfo>() {
@@ -102,10 +106,16 @@
dest.writeBoolean(mReceiveSystemEvents);
dest.writeList(mAllowedSensorIds);
dest.writeBoolean(mAllowBackgroundAuthentication);
+ dest.writeBoolean(mIgnoreEnrollmentState);
+ dest.writeBoolean(mIsForLegacyFingerprintManager);
}
public boolean containsTestConfigurations() {
- if (!mAllowedSensorIds.isEmpty()) {
+ if (mIsForLegacyFingerprintManager
+ && mAllowedSensorIds.size() == 1
+ && !mAllowBackgroundAuthentication) {
+ return false;
+ } else if (!mAllowedSensorIds.isEmpty()) {
return true;
} else if (mAllowBackgroundAuthentication) {
return true;
@@ -185,13 +195,24 @@
}
public void setAllowedSensorIds(@NonNull List<Integer> sensorIds) {
- mAllowedSensorIds = sensorIds;
+ mAllowedSensorIds.clear();
+ mAllowedSensorIds.addAll(sensorIds);
}
public void setAllowBackgroundAuthentication(boolean allow) {
mAllowBackgroundAuthentication = allow;
}
+ public void setIgnoreEnrollmentState(boolean ignoreEnrollmentState) {
+ mIgnoreEnrollmentState = ignoreEnrollmentState;
+ }
+
+ public void setIsForLegacyFingerprintManager(int sensorId) {
+ mIsForLegacyFingerprintManager = true;
+ mAllowedSensorIds.clear();
+ mAllowedSensorIds.add(sensorId);
+ }
+
// Getters
public CharSequence getTitle() {
@@ -261,4 +282,12 @@
public boolean isAllowBackgroundAuthentication() {
return mAllowBackgroundAuthentication;
}
+
+ public boolean isIgnoreEnrollmentState() {
+ return mIgnoreEnrollmentState;
+ }
+
+ public boolean isForLegacyFingerprintManager() {
+ return mIsForLegacyFingerprintManager;
+ }
}
diff --git a/core/java/android/hardware/location/GeofenceHardwareRequestParcelable.java b/core/java/android/hardware/location/GeofenceHardwareRequestParcelable.java
index df13ade..bd25b8f 100644
--- a/core/java/android/hardware/location/GeofenceHardwareRequestParcelable.java
+++ b/core/java/android/hardware/location/GeofenceHardwareRequestParcelable.java
@@ -16,9 +16,9 @@
package android.hardware.location;
+import android.os.BadParcelableException;
import android.os.Parcel;
import android.os.Parcelable;
-import android.util.Log;
/**
* Geofence Hardware Request used for internal location services communication.
@@ -139,11 +139,8 @@
@Override
public GeofenceHardwareRequestParcelable createFromParcel(Parcel parcel) {
int geofenceType = parcel.readInt();
- if(geofenceType != GeofenceHardwareRequest.GEOFENCE_TYPE_CIRCLE) {
- Log.e(
- "GeofenceHardwareRequest",
- String.format("Invalid Geofence type: %d", geofenceType));
- return null;
+ if (geofenceType != GeofenceHardwareRequest.GEOFENCE_TYPE_CIRCLE) {
+ throw new BadParcelableException("Invalid Geofence type: " + geofenceType);
}
GeofenceHardwareRequest request = GeofenceHardwareRequest.createCircularGeofence(
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index e06e7b6..d0a77a0 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -474,6 +474,7 @@
*/
public final void recycle() {
if (DEBUG_RECYCLE) mStack = null;
+ mClassCookies = null;
freeBuffer();
if (mOwnsNativeParcelObject) {
diff --git a/core/java/android/service/gatekeeper/GateKeeperResponse.java b/core/java/android/service/gatekeeper/GateKeeperResponse.java
index 7ed733c..9d648a6 100644
--- a/core/java/android/service/gatekeeper/GateKeeperResponse.java
+++ b/core/java/android/service/gatekeeper/GateKeeperResponse.java
@@ -105,7 +105,7 @@
dest.writeInt(mTimeout);
} else if (mResponseCode == RESPONSE_OK) {
dest.writeInt(mShouldReEnroll ? 1 : 0);
- if (mPayload != null) {
+ if (mPayload != null && mPayload.length > 0) {
dest.writeInt(mPayload.length);
dest.writeByteArray(mPayload);
} else {
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 4dc9807..1e29092 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -239,6 +239,7 @@
private static native int nativeGetGPUContextPriority();
private static native void nativeSetTransformHint(long nativeObject, int transformHint);
private static native int nativeGetTransformHint(long nativeObject);
+ private static native void nativeSanitize(long transactionObject);
@Nullable
@GuardedBy("mLock")
@@ -3439,7 +3440,14 @@
return this;
}
- /**
+ /**
+ * @hide
+ */
+ public void sanitize() {
+ nativeSanitize(mNativeObject);
+ }
+
+ /**
* Merge the other transaction into this transaction, clearing the
* other transaction as if it had been applied.
*
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 42d77cd..f567478 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -2957,7 +2957,7 @@
@UnsupportedAppUsage
public int getInputMethodWindowVisibleHeight() {
try {
- return mService.getInputMethodWindowVisibleHeight();
+ return mService.getInputMethodWindowVisibleHeight(mClient);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/window/SplashScreen.java b/core/java/android/window/SplashScreen.java
index 0c4d273..7d836d4 100644
--- a/core/java/android/window/SplashScreen.java
+++ b/core/java/android/window/SplashScreen.java
@@ -93,8 +93,12 @@
* <p>
* To reset to the default theme, set this the themeId to {@link Resources#ID_NULL}.
* <p>
- * <b>Note:</b> The theme name must be stable across versions, otherwise it won't be found
- * after your application is updated.
+ * <b>Note:</b> Internally, the theme name is resolved and persisted. This means that the theme
+ * name must be stable across versions, otherwise it won't be found after your application is
+ * updated.
+ *
+ * @param themeId The ID of the splashscreen theme to be used in place of the one defined in
+ * the manifest.
*/
void setSplashScreenTheme(@StyleRes int themeId);
diff --git a/core/java/com/android/internal/notification/NotificationAccessConfirmationActivityContract.java b/core/java/com/android/internal/notification/NotificationAccessConfirmationActivityContract.java
index 4ce6f60..fdf0e90 100644
--- a/core/java/com/android/internal/notification/NotificationAccessConfirmationActivityContract.java
+++ b/core/java/com/android/internal/notification/NotificationAccessConfirmationActivityContract.java
@@ -17,6 +17,7 @@
package com.android.internal.notification;
import android.content.ComponentName;
+import android.content.Context;
import android.content.Intent;
public final class NotificationAccessConfirmationActivityContract {
@@ -25,13 +26,14 @@
"com.android.settings.notification.NotificationAccessConfirmationActivity");
public static final String EXTRA_USER_ID = "user_id";
public static final String EXTRA_COMPONENT_NAME = "component_name";
- public static final String EXTRA_PACKAGE_TITLE = "package_title";
- public static Intent launcherIntent(int userId, ComponentName component, String packageTitle) {
+ /**
+ * Creates a launcher intent for NotificationAccessConfirmationActivity.
+ */
+ public static Intent launcherIntent(Context context, int userId, ComponentName component) {
return new Intent()
.setComponent(COMPONENT_NAME)
.putExtra(EXTRA_USER_ID, userId)
- .putExtra(EXTRA_COMPONENT_NAME, component)
- .putExtra(EXTRA_PACKAGE_TITLE, packageTitle);
+ .putExtra(EXTRA_COMPONENT_NAME, component);
}
}
diff --git a/core/java/com/android/internal/policy/IKeyguardStateCallback.aidl b/core/java/com/android/internal/policy/IKeyguardStateCallback.aidl
index 8e454db..a8003a1 100644
--- a/core/java/com/android/internal/policy/IKeyguardStateCallback.aidl
+++ b/core/java/com/android/internal/policy/IKeyguardStateCallback.aidl
@@ -16,7 +16,7 @@
package com.android.internal.policy;
interface IKeyguardStateCallback {
- void onShowingStateChanged(boolean showing);
+ void onShowingStateChanged(boolean showing, int userId);
void onSimSecureStateChanged(boolean simSecure);
void onInputRestrictedStateChanged(boolean inputRestricted);
void onTrustedChanged(boolean trusted);
diff --git a/core/java/com/android/internal/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl
index d40c064..0751213 100644
--- a/core/java/com/android/internal/view/IInputMethodManager.aidl
+++ b/core/java/com/android/internal/view/IInputMethodManager.aidl
@@ -67,7 +67,7 @@
void setAdditionalInputMethodSubtypes(String id, in InputMethodSubtype[] subtypes);
// This is kept due to @UnsupportedAppUsage.
// TODO(Bug 113914148): Consider removing this.
- int getInputMethodWindowVisibleHeight();
+ int getInputMethodWindowVisibleHeight(in IInputMethodClient client);
oneway void reportPerceptibleAsync(in IBinder windowToken, boolean perceptible);
/** Remove the IME surface. Requires INTERNAL_SYSTEM_WINDOW permission. */
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 7f99e29..4cb258d 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -875,6 +875,11 @@
transaction->setDropInputMode(ctrl, static_cast<gui::DropInputMode>(mode));
}
+static void nativeSanitize(JNIEnv* env, jclass clazz, jlong transactionObj) {
+ auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
+ transaction->sanitize();
+}
+
static jlongArray nativeGetPhysicalDisplayIds(JNIEnv* env, jclass clazz) {
const auto displayIds = SurfaceComposerClient::getPhysicalDisplayIds();
jlongArray array = env->NewLongArray(displayIds.size());
@@ -2003,6 +2008,8 @@
(void*)nativeSetTrustedOverlay },
{"nativeSetDropInputMode", "(JJI)V",
(void*)nativeSetDropInputMode},
+ {"nativeSanitize", "(J)V",
+ (void*) nativeSanitize }
// clang-format on
};
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 8db7f4c..0c50e0d 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -99,6 +99,7 @@
<protected-broadcast android:name="android.intent.action.OVERLAY_PRIORITY_CHANGED" />
<protected-broadcast android:name="android.intent.action.MY_PACKAGE_SUSPENDED" />
<protected-broadcast android:name="android.intent.action.MY_PACKAGE_UNSUSPENDED" />
+ <protected-broadcast android:name="android.app.action.MANAGED_PROFILE_PROVISIONED" />
<protected-broadcast android:name="android.os.action.POWER_SAVE_MODE_CHANGED" />
<protected-broadcast android:name="android.os.action.DEVICE_IDLE_MODE_CHANGED" />
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 68f6596..6eaf52e 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -5052,4 +5052,12 @@
<!-- the number of the max cached processes in the system. -->
<integer name="config_customizedMaxCachedProcesses">32</integer>
+
+ <!-- List of system components which are allowed to receive ServiceState entries in an
+ un-sanitized form, even if the location toggle is off. This is intended ONLY for system
+ components, such as the telephony stack, which require access to the full ServiceState for
+ tasks such as network registration. -->
+ <string-array name="config_serviceStateLocationAllowedPackages">
+ <item>"com.android.phone"</item>
+ </string-array>
</resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index ccddc0a..60f7aef 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -4427,4 +4427,5 @@
<java-symbol type="bool" name="config_volumeAdjustmentForRemoteGroupSessions" />
<java-symbol type="integer" name="config_customizedMaxCachedProcesses" />
+ <java-symbol type="array" name="config_serviceStateLocationAllowedPackages" />
</resources>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index c75d018..20bb5fb 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -972,7 +972,7 @@
<string name="instant_apps_message_with_help" msgid="1816952263531203932">"Sovellus avattiin ilman asennusta. Katso lisätietoja napauttamalla."</string>
<string name="app_info" msgid="5153758994129963243">"Sovelluksen tiedot"</string>
<string name="go_to_web" msgid="636673528981366511">"Siirry selaimeen"</string>
- <string name="mobile_data" msgid="4564407557775397216">"Mobiilitiedonsiirto"</string>
+ <string name="mobile_data" msgid="4564407557775397216">"Mobiilidata"</string>
<string name="mobile_data_text_format" msgid="6806501540022589786">"<xliff:g id="ID_1">%1$s</xliff:g> – <xliff:g id="ID_2">%2$s</xliff:g>"</string>
<string name="mobile_carrier_text_format" msgid="8912204177152950766">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>"</string>
<string name="wifi_is_off" msgid="5389597396308001471">"Wi-Fi on pois päältä"</string>
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
index a4123c7..4cad6a6 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
@@ -118,7 +118,7 @@
private class BiometricTaskStackListener extends TaskStackListener {
@Override
public void onTaskStackChanged() {
- mHandler.post(AuthController.this::handleTaskStackChanged);
+ mHandler.post(AuthController.this::cancelIfOwnerIsNotInForeground);
}
}
@@ -181,7 +181,7 @@
}
};
- private void handleTaskStackChanged() {
+ private void cancelIfOwnerIsNotInForeground() {
if (mCurrentDialog != null) {
try {
final String clientPackage = mCurrentDialog.getOpPackageName();
@@ -192,7 +192,7 @@
final String topPackage = runningTasks.get(0).topActivity.getPackageName();
if (!topPackage.contentEquals(clientPackage)
&& !Utils.isSystem(mContext, clientPackage)) {
- Log.w(TAG, "Evicting client due to: " + topPackage);
+ Log.e(TAG, "Evicting client due to: " + topPackage);
mCurrentDialog.dismissWithoutCallback(true /* animate */);
mCurrentDialog = null;
mOrientationListener.disable();
@@ -721,6 +721,10 @@
mCurrentDialog = newDialog;
mCurrentDialog.show(mWindowManager, savedState);
mOrientationListener.enable();
+
+ if (!promptInfo.isAllowBackgroundAuthentication()) {
+ mHandler.post(this::cancelIfOwnerIsNotInForeground);
+ }
}
private void onDialogDismissed(@DismissedReason int reason) {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 1a8af3b..192908f 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -1475,7 +1475,9 @@
public void doKeyguardTimeout(Bundle options) {
mHandler.removeMessages(KEYGUARD_TIMEOUT);
Message msg = mHandler.obtainMessage(KEYGUARD_TIMEOUT, options);
- mHandler.sendMessage(msg);
+ // Treat these messages with priority - A call to timeout means the device should lock
+ // as soon as possible and not wait for other messages on the thread to process first.
+ mHandler.sendMessageAtFrontOfQueue(msg);
}
/**
@@ -1664,12 +1666,15 @@
* @see #handleShow
*/
private void showLocked(Bundle options) {
- Trace.beginSection("KeyguardViewMediator#showLocked aqcuiring mShowKeyguardWakeLock");
+ Trace.beginSection("KeyguardViewMediator#showLocked acquiring mShowKeyguardWakeLock");
if (DEBUG) Log.d(TAG, "showLocked");
// ensure we stay awake until we are finished displaying the keyguard
mShowKeyguardWakeLock.acquire();
Message msg = mHandler.obtainMessage(SHOW, options);
- mHandler.sendMessage(msg);
+ // Treat these messages with priority - This call can originate from #doKeyguardTimeout,
+ // meaning the device should lock as soon as possible and not wait for other messages on
+ // the thread to process first.
+ mHandler.sendMessageAtFrontOfQueue(msg);
Trace.endSection();
}
@@ -1855,6 +1860,7 @@
case KEYGUARD_TIMEOUT:
synchronized (KeyguardViewMediator.this) {
doKeyguardLocked((Bundle) msg.obj);
+ notifyDefaultDisplayCallbacks(mShowing);
}
break;
case DISMISS:
@@ -2843,7 +2849,7 @@
for (int i = size - 1; i >= 0; i--) {
IKeyguardStateCallback callback = mKeyguardStateCallbacks.get(i);
try {
- callback.onShowingStateChanged(showing);
+ callback.onShowingStateChanged(showing, KeyguardUpdateMonitor.getCurrentUser());
} catch (RemoteException e) {
Slog.w(TAG, "Failed to call onShowingStateChanged", e);
if (e instanceof DeadObjectException) {
@@ -2892,7 +2898,7 @@
mKeyguardStateCallbacks.add(callback);
try {
callback.onSimSecureStateChanged(mUpdateMonitor.isSimPinSecure());
- callback.onShowingStateChanged(mShowing);
+ callback.onShowingStateChanged(mShowing, KeyguardUpdateMonitor.getCurrentUser());
callback.onInputRestrictedStateChanged(mInputRestricted);
callback.onTrustedChanged(mUpdateMonitor.getUserHasTrust(
KeyguardUpdateMonitor.getCurrentUser()));
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java
index 433d5e1..8313299 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java
@@ -175,9 +175,86 @@
*/
@Override
public boolean shouldLaunchFullScreenIntentWhenAdded(NotificationEntry entry) {
- return entry.getSbn().getNotification().fullScreenIntent != null
- && (!shouldHeadsUp(entry)
- || mStatusBarStateController.getState() == StatusBarState.KEYGUARD);
+ if (entry.getSbn().getNotification().fullScreenIntent == null) {
+ return false;
+ }
+
+ // Never show FSI when suppressed by DND
+ if (entry.shouldSuppressFullScreenIntent()) {
+ if (DEBUG) {
+ Log.d(TAG, "No FullScreenIntent: Suppressed by DND: " + entry.getKey());
+ }
+ return false;
+ }
+
+ // Never show FSI if importance is not HIGH
+ if (entry.getImportance() < NotificationManager.IMPORTANCE_HIGH) {
+ if (DEBUG) {
+ Log.d(TAG, "No FullScreenIntent: Not important enough: " + entry.getKey());
+ }
+ return false;
+ }
+
+ // If the notification has suppressive GroupAlertBehavior, block FSI and warn.
+ StatusBarNotification sbn = entry.getSbn();
+ if (sbn.isGroup() && sbn.getNotification().suppressAlertingDueToGrouping()) {
+ // b/231322873: Detect and report an event when a notification has both an FSI and a
+ // suppressive groupAlertBehavior, and now correctly block the FSI from firing.
+ final int uid = entry.getSbn().getUid();
+ android.util.EventLog.writeEvent(0x534e4554, "231322873", uid, "groupAlertBehavior");
+ if (DEBUG) {
+ Log.w(TAG, "No FullScreenIntent: WARNING: GroupAlertBehavior will prevent HUN: "
+ + entry.getKey());
+ }
+ return false;
+ }
+
+ // If the screen is off, then launch the FullScreenIntent
+ if (!mPowerManager.isInteractive()) {
+ if (DEBUG) {
+ Log.d(TAG, "FullScreenIntent: Device is not interactive: " + entry.getKey());
+ }
+ return true;
+ }
+
+ // If the device is currently dreaming, then launch the FullScreenIntent
+ if (isDreaming()) {
+ if (DEBUG) {
+ Log.d(TAG, "FullScreenIntent: Device is dreaming: " + entry.getKey());
+ }
+ return true;
+ }
+
+ // If the keyguard is showing, then launch the FullScreenIntent
+ if (mStatusBarStateController.getState() == StatusBarState.KEYGUARD) {
+ if (DEBUG) {
+ Log.d(TAG, "FullScreenIntent: Keyguard is showing: " + entry.getKey());
+ }
+ return true;
+ }
+
+ // If the notification should HUN, then we don't need FSI
+ if (shouldHeadsUp(entry)) {
+ if (DEBUG) {
+ Log.d(TAG, "No FullScreenIntent: Expected to HUN: " + entry.getKey());
+ }
+ return false;
+ }
+
+ // If the notification won't HUN for some other reason (DND/snooze/etc), launch FSI.
+ if (DEBUG) {
+ Log.d(TAG, "FullScreenIntent: Expected not to HUN: " + entry.getKey());
+ }
+ return true;
+ }
+
+ private boolean isDreaming() {
+ try {
+ return mDreamManager.isDreaming();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to query dream manager.", e);
+ return false;
+ }
}
private boolean shouldHeadsUpWhenAwake(NotificationEntry entry) {
@@ -228,13 +305,7 @@
return false;
}
- boolean isDreaming = false;
- try {
- isDreaming = mDreamManager.isDreaming();
- } catch (RemoteException e) {
- Log.e(TAG, "Failed to query dream manager.", e);
- }
- boolean inUse = mPowerManager.isScreenOn() && !isDreaming;
+ boolean inUse = mPowerManager.isScreenOn() && !isDreaming();
if (!inUse) {
if (DEBUG_HEADS_UP) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
index 3ceb655..b1bea76 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
@@ -329,6 +329,13 @@
};
/**
+ * Recalculate sensitiveness without animation; called when waking up while keyguard occluded.
+ */
+ public void updateSensitivenessForOccludedWakeup() {
+ mView.updateSensitiveness(false, mLockscreenUserManager.isAnyProfilePublicMode());
+ }
+
+ /**
* Set the overexpansion of the panel to be applied to the view.
*/
public void setOverExpansion(float overExpansion) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 871fb01..6aee09c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -4159,6 +4159,17 @@
mWakeUpCoordinator.setFullyAwake(true);
mBypassHeadsUpNotifier.setFullyAwake(true);
mWakeUpCoordinator.setWakingUp(false);
+ if (isOccluded() && !mDozeParameters.canControlUnlockedScreenOff()) {
+ // When the keyguard is occluded we don't use the KEYGUARD state which would
+ // normally cause these redaction updates. If AOD is on, the KEYGUARD state is used
+ // to show the doze, AND UnlockedScreenOffAnimationController.onFinishedWakingUp()
+ // would force a KEYGUARD state that would take care of recalculating redaction.
+ // So if AOD is off or unsupported we need to trigger these updates at screen on
+ // when the keyguard is occluded.
+ mLockscreenUserManager.updatePublicMode();
+ mNotificationPanelViewController.getNotificationStackScrollLayoutController()
+ .updateSensitivenessForOccludedWakeup();
+ }
if (mLaunchCameraWhenFinishedWaking) {
mNotificationPanelViewController.launchCamera(
false /* animate */, mLastCameraLaunchSource);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt
index 6982631..e464258 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt
@@ -21,7 +21,7 @@
import android.app.IUidObserver
import android.app.Notification
import android.app.Notification.CallStyle.CALL_TYPE_ONGOING
-import android.content.Intent
+import android.app.PendingIntent
import android.util.Log
import android.view.View
import android.widget.Chronometer
@@ -86,7 +86,7 @@
val newOngoingCallInfo = CallNotificationInfo(
entry.sbn.key,
entry.sbn.notification.`when`,
- entry.sbn.notification.contentIntent?.intent,
+ entry.sbn.notification.contentIntent,
entry.sbn.uid,
entry.sbn.notification.extras.getInt(
Notification.EXTRA_CALL_TYPE, -1) == CALL_TYPE_ONGOING
@@ -188,7 +188,6 @@
logger.logChipClicked()
activityStarter.postStartActivityDismissingKeyguard(
intent,
- 0,
ActivityLaunchAnimator.Controller.fromView(
backgroundView,
InteractionJankMonitor.CUJ_STATUS_BAR_APP_LAUNCH_FROM_CALL_CHIP)
@@ -277,7 +276,7 @@
private data class CallNotificationInfo(
val key: String,
val callStartTime: Long,
- val intent: Intent?,
+ val intent: PendingIntent?,
val uid: Int,
/** True if the call is currently ongoing (as opposed to incoming, screening, etc.). */
val isOngoing: Boolean
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
index 39d5314..5488655 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
@@ -486,15 +486,25 @@
}
@Test
+ public void testClientNotified_whenTaskStackChangesDuringShow() throws Exception {
+ switchTask("other_package");
+ showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */);
+
+ waitForIdleSync();
+
+ assertNull(mAuthController.mCurrentDialog);
+ assertNull(mAuthController.mReceiver);
+ verify(mDialog1).dismissWithoutCallback(true /* animate */);
+ verify(mReceiver).onDialogDismissed(
+ eq(BiometricPrompt.DISMISSED_REASON_USER_CANCEL),
+ eq(null) /* credentialAttestation */);
+ }
+
+ @Test
public void testClientNotified_whenTaskStackChangesDuringAuthentication() throws Exception {
showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */);
- List<ActivityManager.RunningTaskInfo> tasks = new ArrayList<>();
- ActivityManager.RunningTaskInfo taskInfo = mock(ActivityManager.RunningTaskInfo.class);
- taskInfo.topActivity = mock(ComponentName.class);
- when(taskInfo.topActivity.getPackageName()).thenReturn("other_package");
- tasks.add(taskInfo);
- when(mActivityTaskManager.getTasks(anyInt())).thenReturn(tasks);
+ switchTask("other_package");
mAuthController.mTaskStackListener.onTaskStackChanged();
waitForIdleSync();
@@ -570,6 +580,16 @@
BIOMETRIC_MULTI_SENSOR_FACE_THEN_FINGERPRINT);
}
+ private void switchTask(String packageName) {
+ final List<ActivityManager.RunningTaskInfo> tasks = new ArrayList<>();
+ final ActivityManager.RunningTaskInfo taskInfo =
+ mock(ActivityManager.RunningTaskInfo.class);
+ taskInfo.topActivity = mock(ComponentName.class);
+ when(taskInfo.topActivity.getPackageName()).thenReturn(packageName);
+ tasks.add(taskInfo);
+ when(mActivityTaskManager.getTasks(anyInt())).thenReturn(tasks);
+ }
+
private PromptInfo createTestPromptInfo() {
PromptInfo promptInfo = new PromptInfo();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
index ad08780..a21e17f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
@@ -61,6 +61,7 @@
import com.android.systemui.util.time.FakeSystemClock;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
@@ -129,6 +130,7 @@
mViewMediator.onSystemReady();
}
+ @Ignore("flaky, b/223385977")
@Test
public void testOnGoingToSleep_UpdatesKeyguardGoingAway() {
mViewMediator.onStartedGoingToSleep(OFF_BECAUSE_OF_USER);
@@ -136,12 +138,14 @@
verify(mStatusBarKeyguardViewManager, never()).setKeyguardGoingAwayState(anyBoolean());
}
+ @Ignore("flaky, b/223385977")
@Test
public void testRegisterDumpable() {
verify(mDumpManager).registerDumpable(KeyguardViewMediator.class.getName(), mViewMediator);
verify(mStatusBarKeyguardViewManager, never()).setKeyguardGoingAwayState(anyBoolean());
}
+ @Ignore("flaky, b/223385977")
@Test
public void testKeyguardGone_notGoingaway() {
mViewMediator.mViewMediatorCallback.keyguardGone();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java
index 60c3bc8..440f76a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java
@@ -24,6 +24,7 @@
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK;
import static com.android.systemui.statusbar.NotificationEntryHelper.modifyRanking;
+import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
import static com.android.systemui.statusbar.StatusBarState.SHADE;
import static com.google.common.truth.Truth.assertThat;
@@ -84,6 +85,8 @@
BatteryController mBatteryController;
@Mock
Handler mMockHandler;
+ @Mock
+ PendingIntent mPendingIntent;
private NotificationInterruptStateProviderImpl mNotifInterruptionStateProvider;
@@ -399,6 +402,97 @@
assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isFalse();
}
+ @Test
+ public void testShouldNotFullScreen_notPendingIntent() throws RemoteException {
+ NotificationEntry entry = createNotification(IMPORTANCE_HIGH);
+ when(mPowerManager.isInteractive()).thenReturn(true);
+ when(mDreamManager.isDreaming()).thenReturn(false);
+ when(mStatusBarStateController.getState()).thenReturn(SHADE);
+
+ assertThat(mNotifInterruptionStateProvider.shouldLaunchFullScreenIntentWhenAdded(entry))
+ .isFalse();
+ }
+
+ @Test
+ public void testShouldNotFullScreen_notHighImportance() throws RemoteException {
+ NotificationEntry entry = createFsiNotification(IMPORTANCE_DEFAULT, /* silenced */ false);
+ when(mPowerManager.isInteractive()).thenReturn(true);
+ when(mDreamManager.isDreaming()).thenReturn(false);
+ when(mStatusBarStateController.getState()).thenReturn(SHADE);
+
+ assertThat(mNotifInterruptionStateProvider.shouldLaunchFullScreenIntentWhenAdded(entry))
+ .isFalse();
+ }
+
+ @Test
+ public void testShouldNotFullScreen_isGroupAlertSilenced() throws RemoteException {
+ NotificationEntry entry = createFsiNotification(IMPORTANCE_HIGH, /* silenced */ true);
+ when(mPowerManager.isInteractive()).thenReturn(false);
+ when(mDreamManager.isDreaming()).thenReturn(true);
+ when(mStatusBarStateController.getState()).thenReturn(KEYGUARD);
+
+ assertThat(mNotifInterruptionStateProvider.shouldLaunchFullScreenIntentWhenAdded(entry))
+ .isFalse();
+ }
+
+ @Test
+ public void testShouldFullScreen_notInteractive() throws RemoteException {
+ NotificationEntry entry = createFsiNotification(IMPORTANCE_HIGH, /* silenced */ false);
+ when(mPowerManager.isInteractive()).thenReturn(false);
+ when(mDreamManager.isDreaming()).thenReturn(false);
+ when(mStatusBarStateController.getState()).thenReturn(SHADE);
+
+ assertThat(mNotifInterruptionStateProvider.shouldLaunchFullScreenIntentWhenAdded(entry))
+ .isTrue();
+ }
+
+ @Test
+ public void testShouldFullScreen_isDreaming() throws RemoteException {
+ NotificationEntry entry = createFsiNotification(IMPORTANCE_HIGH, /* silenced */ false);
+ when(mPowerManager.isInteractive()).thenReturn(true);
+ when(mDreamManager.isDreaming()).thenReturn(true);
+ when(mStatusBarStateController.getState()).thenReturn(SHADE);
+
+ assertThat(mNotifInterruptionStateProvider.shouldLaunchFullScreenIntentWhenAdded(entry))
+ .isTrue();
+ }
+
+ @Test
+ public void testShouldFullScreen_onKeyguard() throws RemoteException {
+ NotificationEntry entry = createFsiNotification(IMPORTANCE_HIGH, /* silenced */ false);
+ when(mPowerManager.isInteractive()).thenReturn(true);
+ when(mDreamManager.isDreaming()).thenReturn(false);
+ when(mStatusBarStateController.getState()).thenReturn(KEYGUARD);
+
+ assertThat(mNotifInterruptionStateProvider.shouldLaunchFullScreenIntentWhenAdded(entry))
+ .isTrue();
+ }
+
+ @Test
+ public void testShouldNotFullScreen_willHun() throws RemoteException {
+ NotificationEntry entry = createFsiNotification(IMPORTANCE_HIGH, /* silenced */ false);
+ when(mPowerManager.isInteractive()).thenReturn(true);
+ when(mPowerManager.isScreenOn()).thenReturn(true);
+ when(mDreamManager.isDreaming()).thenReturn(false);
+ when(mStatusBarStateController.getState()).thenReturn(SHADE);
+
+ assertThat(mNotifInterruptionStateProvider.shouldLaunchFullScreenIntentWhenAdded(entry))
+ .isFalse();
+ }
+
+ @Test
+ public void testShouldFullScreen_packageSnoozed() throws RemoteException {
+ NotificationEntry entry = createFsiNotification(IMPORTANCE_HIGH, /* silenced */ false);
+ when(mPowerManager.isInteractive()).thenReturn(true);
+ when(mPowerManager.isScreenOn()).thenReturn(true);
+ when(mDreamManager.isDreaming()).thenReturn(false);
+ when(mStatusBarStateController.getState()).thenReturn(SHADE);
+ when(mHeadsUpManager.isSnoozed("a")).thenReturn(true);
+
+ assertThat(mNotifInterruptionStateProvider.shouldLaunchFullScreenIntentWhenAdded(entry))
+ .isTrue();
+ }
+
/**
* Bubbles can happen.
*/
@@ -503,6 +597,10 @@
.setContentText("content text")
.build();
+ return createNotification(importance, n);
+ }
+
+ private NotificationEntry createNotification(int importance, Notification n) {
return new NotificationEntryBuilder()
.setPkg("a")
.setOpPkg("a")
@@ -512,6 +610,20 @@
.build();
}
+ private NotificationEntry createFsiNotification(int importance, boolean silent) {
+ Notification n = new Notification.Builder(getContext(), "a")
+ .setContentTitle("title")
+ .setContentText("content text")
+ .setFullScreenIntent(mPendingIntent, true)
+ .setGroup("fsi")
+ .setGroupAlertBehavior(silent
+ ? Notification.GROUP_ALERT_SUMMARY
+ : Notification.GROUP_ALERT_ALL)
+ .build();
+
+ return createNotification(importance, n);
+ }
+
private final NotificationInterruptSuppressor
mSuppressAwakeHeadsUp =
new NotificationInterruptSuppressor() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt
index d26db4c..b3e2469 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt
@@ -22,7 +22,6 @@
import android.app.Notification
import android.app.PendingIntent
import android.app.Person
-import android.content.Intent
import android.service.notification.NotificationListenerService.REASON_USER_STOPPED
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
@@ -401,6 +400,19 @@
.isEqualTo(OngoingCallLogger.OngoingCallEvents.ONGOING_CALL_CLICKED.id)
}
+ /** Regression test for b/212467440. */
+ @Test
+ fun chipClicked_activityStarterTriggeredWithUnmodifiedIntent() {
+ val notifEntry = createOngoingCallNotifEntry()
+ val pendingIntent = notifEntry.sbn.notification.contentIntent
+ notifCollectionListener.onEntryUpdated(notifEntry)
+
+ chipView.performClick()
+
+ // Ensure that the sysui didn't modify the notification's intent -- see b/212467440.
+ verify(mockActivityStarter).postStartActivityDismissingKeyguard(eq(pendingIntent), any())
+ }
+
@Test
fun notifyChipVisibilityChanged_visibleEventLogged() {
controller.notifyChipVisibilityChanged(true)
@@ -428,7 +440,6 @@
notificationEntryBuilder.modifyNotification(context).setContentIntent(null)
} else {
val contentIntent = mock(PendingIntent::class.java)
- `when`(contentIntent.intent).thenReturn(mock(Intent::class.java))
notificationEntryBuilder.modifyNotification(context).setContentIntent(contentIntent)
}
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index 30de4b4..5952182 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -74,7 +74,6 @@
import android.content.SharedPreferences;
import android.content.pm.FeatureInfo;
import android.content.pm.PackageInfo;
-import android.content.pm.PackageItemInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.content.pm.ResolveInfo;
@@ -553,20 +552,12 @@
String callingPackage = component.getPackageName();
checkCanCallNotificationApi(callingPackage);
int userId = getCallingUserId();
- String packageTitle = BidiFormatter.getInstance().unicodeWrap(
- getPackageInfo(callingPackage, userId)
- .applicationInfo
- .loadSafeLabel(getContext().getPackageManager(),
- PackageItemInfo.DEFAULT_MAX_LABEL_SIZE_PX,
- PackageItemInfo.SAFE_LABEL_FLAG_TRIM
- | PackageItemInfo.SAFE_LABEL_FLAG_FIRST_LINE)
- .toString());
final long identity = Binder.clearCallingIdentity();
try {
return PendingIntent.getActivityAsUser(getContext(),
0 /* request code */,
NotificationAccessConfirmationActivityContract.launcherIntent(
- userId, component, packageTitle),
+ getContext(), userId, component),
PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_ONE_SHOT
| PendingIntent.FLAG_CANCEL_CURRENT,
null /* options */,
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 69c2926..0a23ab8 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -128,6 +128,7 @@
import android.util.ArraySet;
import android.util.AtomicFile;
import android.util.DataUnit;
+import android.util.EventLog;
import android.util.Log;
import android.util.Pair;
import android.util.Slog;
@@ -3398,7 +3399,21 @@
}
}
} catch (Exception e) {
+ EventLog.writeEvent(0x534e4554, "224585613", -1, "");
Slog.wtf(TAG, e);
+ // Make sure to re-throw this exception; we must not ignore failure
+ // to prepare the user storage as it could indicate that encryption
+ // wasn't successfully set up.
+ //
+ // Very unfortunately, these errors need to be ignored for broken
+ // users that already existed on-disk from older Android versions.
+ UserManagerInternal umInternal = LocalServices.getService(UserManagerInternal.class);
+ if (umInternal.shouldIgnorePrepareStorageErrors(userId)) {
+ Slog.wtf(TAG, "ignoring error preparing storage for existing user " + userId
+ + "; device may be insecure!");
+ return;
+ }
+ throw new RuntimeException(e);
}
}
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 1d8d179..f0c9817 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -2853,42 +2853,88 @@
Binder.restoreCallingIdentity(ident);
}
+ // Send the broadcast exactly once to all possible disjoint sets of apps.
+ // If the location master switch is on, broadcast the ServiceState 4 times:
+ // - Full ServiceState sent to apps with ACCESS_FINE_LOCATION and READ_PHONE_STATE
+ // - Full ServiceState sent to apps with ACCESS_FINE_LOCATION and
+ // READ_PRIVILEGED_PHONE_STATE but not READ_PHONE_STATE
+ // - Sanitized ServiceState sent to apps with READ_PHONE_STATE but not ACCESS_FINE_LOCATION
+ // - Sanitized ServiceState sent to apps with READ_PRIVILEGED_PHONE_STATE but neither
+ // READ_PHONE_STATE nor ACCESS_FINE_LOCATION
+ // If the location master switch is off, broadcast the ServiceState multiple times:
+ // - Full ServiceState sent to all apps permitted to bypass the location master switch if
+ // they have either READ_PHONE_STATE or READ_PRIVILEGED_PHONE_STATE
+ // - Sanitized ServiceState sent to all other apps with READ_PHONE_STATE
+ // - Sanitized ServiceState sent to all other apps with READ_PRIVILEGED_PHONE_STATE but not
+ // READ_PHONE_STATE
+ if (Binder.withCleanCallingIdentity(() ->
+ LocationAccessPolicy.isLocationModeEnabled(mContext, mContext.getUserId()))) {
+ Intent fullIntent = createServiceStateIntent(state, subId, phoneId, false);
+ mContext.createContextAsUser(UserHandle.ALL, 0).sendBroadcastMultiplePermissions(
+ fullIntent,
+ new String[]{Manifest.permission.READ_PHONE_STATE,
+ Manifest.permission.ACCESS_FINE_LOCATION});
+ mContext.createContextAsUser(UserHandle.ALL, 0).sendBroadcastMultiplePermissions(
+ fullIntent,
+ new String[]{Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
+ Manifest.permission.ACCESS_FINE_LOCATION},
+ new String[]{Manifest.permission.READ_PHONE_STATE});
+
+ Intent sanitizedIntent = createServiceStateIntent(state, subId, phoneId, true);
+ mContext.createContextAsUser(UserHandle.ALL, 0).sendBroadcastMultiplePermissions(
+ sanitizedIntent,
+ new String[]{Manifest.permission.READ_PHONE_STATE},
+ new String[]{Manifest.permission.ACCESS_FINE_LOCATION});
+ mContext.createContextAsUser(UserHandle.ALL, 0).sendBroadcastMultiplePermissions(
+ sanitizedIntent,
+ new String[]{Manifest.permission.READ_PRIVILEGED_PHONE_STATE},
+ new String[]{Manifest.permission.READ_PHONE_STATE,
+ Manifest.permission.ACCESS_FINE_LOCATION});
+ } else {
+ String[] locationBypassPackages = Binder.withCleanCallingIdentity(() ->
+ LocationAccessPolicy.getLocationBypassPackages(mContext));
+ for (String locationBypassPackage : locationBypassPackages) {
+ Intent fullIntent = createServiceStateIntent(state, subId, phoneId, false);
+ fullIntent.setPackage(locationBypassPackage);
+ mContext.createContextAsUser(UserHandle.ALL, 0).sendBroadcastMultiplePermissions(
+ fullIntent,
+ new String[]{Manifest.permission.READ_PHONE_STATE});
+ mContext.createContextAsUser(UserHandle.ALL, 0).sendBroadcastMultiplePermissions(
+ fullIntent,
+ new String[]{Manifest.permission.READ_PRIVILEGED_PHONE_STATE},
+ new String[]{Manifest.permission.READ_PHONE_STATE});
+ }
+
+ Intent sanitizedIntent = createServiceStateIntent(state, subId, phoneId, true);
+ mContext.createContextAsUser(UserHandle.ALL, 0).sendBroadcastMultiplePermissions(
+ sanitizedIntent,
+ new String[]{Manifest.permission.READ_PHONE_STATE},
+ new String[]{/* no excluded permissions */},
+ locationBypassPackages);
+ mContext.createContextAsUser(UserHandle.ALL, 0).sendBroadcastMultiplePermissions(
+ sanitizedIntent,
+ new String[]{Manifest.permission.READ_PRIVILEGED_PHONE_STATE},
+ new String[]{Manifest.permission.READ_PHONE_STATE},
+ locationBypassPackages);
+ }
+ }
+
+ private Intent createServiceStateIntent(ServiceState state, int subId, int phoneId,
+ boolean sanitizeLocation) {
Intent intent = new Intent(Intent.ACTION_SERVICE_STATE);
intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
Bundle data = new Bundle();
- state.fillInNotifierBundle(data);
+ if (sanitizeLocation) {
+ state.createLocationInfoSanitizedCopy(true).fillInNotifierBundle(data);
+ } else {
+ state.fillInNotifierBundle(data);
+ }
intent.putExtras(data);
- // Pass the subscription along with the intent.
intent.putExtra(PHONE_CONSTANTS_SUBSCRIPTION_KEY, subId);
intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, subId);
intent.putExtra(PHONE_CONSTANTS_SLOT_KEY, phoneId);
intent.putExtra(SubscriptionManager.EXTRA_SLOT_INDEX, phoneId);
-
- // Send the broadcast twice -- once for all apps with READ_PHONE_STATE, then again
- // for all apps with READ_PRIVILEGED_PHONE_STATE but not READ_PHONE_STATE.
- // Do this again twice, the first time for apps with ACCESS_FINE_LOCATION, then again with
- // the location-sanitized service state for all apps without ACCESS_FINE_LOCATION.
- // This ensures that any app holding either READ_PRIVILEGED_PHONE_STATE or READ_PHONE_STATE
- // get this broadcast exactly once, and we are not exposing location without permission.
- mContext.createContextAsUser(UserHandle.ALL, 0).sendBroadcastMultiplePermissions(intent,
- new String[] {Manifest.permission.READ_PHONE_STATE,
- Manifest.permission.ACCESS_FINE_LOCATION});
- mContext.createContextAsUser(UserHandle.ALL, 0).sendBroadcastMultiplePermissions(intent,
- new String[] {Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
- Manifest.permission.ACCESS_FINE_LOCATION},
- new String[] {Manifest.permission.READ_PHONE_STATE});
-
- // Replace bundle with location-sanitized ServiceState
- data = new Bundle();
- state.createLocationInfoSanitizedCopy(true).fillInNotifierBundle(data);
- intent.putExtras(data);
- mContext.createContextAsUser(UserHandle.ALL, 0).sendBroadcastMultiplePermissions(intent,
- new String[] {Manifest.permission.READ_PHONE_STATE},
- new String[] {Manifest.permission.ACCESS_FINE_LOCATION});
- mContext.createContextAsUser(UserHandle.ALL, 0).sendBroadcastMultiplePermissions(intent,
- new String[] {Manifest.permission.READ_PRIVILEGED_PHONE_STATE},
- new String[] {Manifest.permission.READ_PHONE_STATE,
- Manifest.permission.ACCESS_FINE_LOCATION});
+ return intent;
}
private void broadcastSignalStrengthChanged(SignalStrength signalStrength, int phoneId,
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 400b084..ae2f934 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -1819,6 +1819,14 @@
if (account == null) {
return false;
}
+ if (account.name != null && account.name.length() > 200) {
+ Log.w(TAG, "Account cannot be added - Name longer than 200 chars");
+ return false;
+ }
+ if (account.type != null && account.type.length() > 200) {
+ Log.w(TAG, "Account cannot be added - Name longer than 200 chars");
+ return false;
+ }
if (!isLocalUnlockedUser(accounts.userId)) {
Log.w(TAG, "Account " + account.toSafeString() + " cannot be added - user "
+ accounts.userId + " is locked. callingUid=" + callingUid);
@@ -2064,6 +2072,10 @@
+ ", pid " + Binder.getCallingPid());
}
if (accountToRename == null) throw new IllegalArgumentException("account is null");
+ if (newName != null && newName.length() > 200) {
+ Log.e(TAG, "renameAccount failed - account name longer than 200");
+ throw new IllegalArgumentException("account name longer than 200");
+ }
int userId = UserHandle.getCallingUserId();
if (!isAccountManagedByCaller(accountToRename.type, callingUid, userId)) {
String msg = String.format(
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index a2fec27..49bfd4d 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -5992,10 +5992,16 @@
}
if (ret == REASON_DENIED) {
- final boolean isAllowedPackage =
- mAllowListWhileInUsePermissionInFgs.contains(callingPackage);
- if (isAllowedPackage) {
- ret = REASON_ALLOWLISTED_PACKAGE;
+ if (verifyPackage(callingPackage, callingUid)) {
+ final boolean isAllowedPackage =
+ mAllowListWhileInUsePermissionInFgs.contains(callingPackage);
+ if (isAllowedPackage) {
+ ret = REASON_ALLOWLISTED_PACKAGE;
+ }
+ } else {
+ EventLog.writeEvent(0x534e4554, "215003903", callingUid,
+ "callingPackage:" + callingPackage + " does not belong to callingUid:"
+ + callingUid);
}
}
@@ -6378,4 +6384,21 @@
/* allowBackgroundActivityStarts */ false)
!= REASON_DENIED;
}
+
+ /**
+ * Checks if a given packageName belongs to a given uid.
+ * @param packageName the package of the caller
+ * @param uid the uid of the caller
+ * @return true or false
+ */
+ private boolean verifyPackage(String packageName, int uid) {
+ if (uid == ROOT_UID || uid == SYSTEM_UID) {
+ //System and Root are always allowed
+ return true;
+ }
+ final int userId = UserHandle.getUserId(uid);
+ final int packageUid = mAm.getPackageManagerInternal()
+ .getPackageUid(packageName, PackageManager.MATCH_DEBUG_TRIAGED_MISSING, userId);
+ return UserHandle.isSameApp(uid, packageUid);
+ }
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 953e6e2..66e3246 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -2544,7 +2544,7 @@
public void batterySendBroadcast(Intent intent) {
synchronized (this) {
broadcastIntentLocked(null, null, null, intent, null, null, 0, null, null, null, null,
- OP_NONE, null, false, false, -1, SYSTEM_UID, Binder.getCallingUid(),
+ null, OP_NONE, null, false, false, -1, SYSTEM_UID, Binder.getCallingUid(),
Binder.getCallingPid(), UserHandle.USER_ALL);
}
}
@@ -4009,7 +4009,7 @@
intent.putExtra(Intent.EXTRA_UID, uid);
intent.putExtra(Intent.EXTRA_USER_HANDLE, UserHandle.getUserId(uid));
broadcastIntentLocked(null, null, null, intent,
- null, null, 0, null, null, null, null, OP_NONE,
+ null, null, 0, null, null, null, null, null, OP_NONE,
null, false, false, MY_PID, SYSTEM_UID, Binder.getCallingUid(),
Binder.getCallingPid(), UserHandle.getUserId(uid));
}
@@ -7686,7 +7686,7 @@
| Intent.FLAG_RECEIVER_FOREGROUND);
intent.putExtra(Intent.EXTRA_USER_HANDLE, currentUserId);
broadcastIntentLocked(null, null, null, intent,
- null, null, 0, null, null, null, null, OP_NONE,
+ null, null, 0, null, null, null, null, null, OP_NONE,
null, false, false, MY_PID, SYSTEM_UID, callingUid, callingPid,
currentUserId);
intent = new Intent(Intent.ACTION_USER_STARTING);
@@ -7698,8 +7698,8 @@
public void performReceive(Intent intent, int resultCode,
String data, Bundle extras, boolean ordered, boolean sticky,
int sendingUser) {}
- }, 0, null, null, new String[] {INTERACT_ACROSS_USERS}, null, OP_NONE,
- null, true, false, MY_PID, SYSTEM_UID, callingUid, callingPid,
+ }, 0, null, null, new String[] {INTERACT_ACROSS_USERS}, null, null,
+ OP_NONE, null, true, false, MY_PID, SYSTEM_UID, callingUid, callingPid,
UserHandle.USER_ALL);
} catch (Throwable e) {
Slog.wtf(TAG, "Failed sending first user broadcasts", e);
@@ -12504,8 +12504,8 @@
Intent intent = allSticky.get(i);
BroadcastQueue queue = broadcastQueueForIntent(intent);
BroadcastRecord r = new BroadcastRecord(queue, intent, null,
- null, null, -1, -1, false, null, null, null, OP_NONE, null, receivers,
- null, 0, null, null, false, true, true, -1, false, null,
+ null, null, -1, -1, false, null, null, null, null, OP_NONE, null,
+ receivers, null, 0, null, null, false, true, true, -1, false, null,
false /* only PRE_BOOT_COMPLETED should be exempt, no stickies */);
queue.enqueueParallelBroadcastLocked(r);
queue.scheduleBroadcastsLocked();
@@ -12747,12 +12747,14 @@
String callerPackage, String callerFeatureId, Intent intent, String resolvedType,
IIntentReceiver resultTo, int resultCode, String resultData,
Bundle resultExtras, String[] requiredPermissions, String[] excludedPermissions,
- int appOp, Bundle bOptions, boolean ordered, boolean sticky, int callingPid,
+ String[] excludedPackages, int appOp, Bundle bOptions, boolean ordered,
+ boolean sticky, int callingPid,
int callingUid, int realCallingUid, int realCallingPid, int userId) {
return broadcastIntentLocked(callerApp, callerPackage, callerFeatureId, intent,
resolvedType, resultTo, resultCode, resultData, resultExtras, requiredPermissions,
- excludedPermissions, appOp, bOptions, ordered, sticky, callingPid, callingUid,
- realCallingUid, realCallingPid, userId, false /* allowBackgroundActivityStarts */,
+ excludedPermissions, excludedPackages, appOp, bOptions, ordered, sticky, callingPid,
+ callingUid, realCallingUid, realCallingPid, userId,
+ false /* allowBackgroundActivityStarts */,
null /* tokenNeededForBackgroundActivityStarts */, null /* broadcastAllowList */);
}
@@ -12761,7 +12763,7 @@
@Nullable String callerFeatureId, Intent intent, String resolvedType,
IIntentReceiver resultTo, int resultCode, String resultData,
Bundle resultExtras, String[] requiredPermissions,
- String[] excludedPermissions, int appOp, Bundle bOptions,
+ String[] excludedPermissions, String[] excludedPackages, int appOp, Bundle bOptions,
boolean ordered, boolean sticky, int callingPid, int callingUid,
int realCallingUid, int realCallingPid, int userId,
boolean allowBackgroundActivityStarts,
@@ -13338,10 +13340,10 @@
final BroadcastQueue queue = broadcastQueueForIntent(intent);
BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp, callerPackage,
callerFeatureId, callingPid, callingUid, callerInstantApp, resolvedType,
- requiredPermissions, excludedPermissions, appOp, brOptions, registeredReceivers,
- resultTo, resultCode, resultData, resultExtras, ordered, sticky, false, userId,
- allowBackgroundActivityStarts, backgroundActivityStartsToken,
- timeoutExempt);
+ requiredPermissions, excludedPermissions, excludedPackages, appOp, brOptions,
+ registeredReceivers, resultTo, resultCode, resultData, resultExtras, ordered,
+ sticky, false, userId, allowBackgroundActivityStarts,
+ backgroundActivityStartsToken, timeoutExempt);
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing parallel broadcast " + r);
final boolean replaced = replacePending
&& (queue.replaceParallelBroadcastLocked(r) != null);
@@ -13436,7 +13438,7 @@
BroadcastQueue queue = broadcastQueueForIntent(intent);
BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp, callerPackage,
callerFeatureId, callingPid, callingUid, callerInstantApp, resolvedType,
- requiredPermissions, excludedPermissions, appOp, brOptions,
+ requiredPermissions, excludedPermissions, excludedPackages, appOp, brOptions,
receivers, resultTo, resultCode, resultData, resultExtras,
ordered, sticky, false, userId, allowBackgroundActivityStarts,
backgroundActivityStartsToken, timeoutExempt);
@@ -13565,14 +13567,16 @@
String[] requiredPermissions, int appOp, Bundle bOptions,
boolean serialized, boolean sticky, int userId) {
return broadcastIntentWithFeature(caller, null, intent, resolvedType, resultTo, resultCode,
- resultData, resultExtras, requiredPermissions, null, appOp, bOptions, serialized,
- sticky, userId);
+ resultData, resultExtras, requiredPermissions, null, null, appOp, bOptions,
+ serialized, sticky, userId);
}
+ @Override
public final int broadcastIntentWithFeature(IApplicationThread caller, String callingFeatureId,
Intent intent, String resolvedType, IIntentReceiver resultTo,
int resultCode, String resultData, Bundle resultExtras,
- String[] requiredPermissions, String[] excludedPermissions, int appOp, Bundle bOptions,
+ String[] requiredPermissions, String[] excludedPermissions,
+ String[] excludedPackages, int appOp, Bundle bOptions,
boolean serialized, boolean sticky, int userId) {
enforceNotIsolatedCaller("broadcastIntent");
synchronized(this) {
@@ -13587,8 +13591,8 @@
return broadcastIntentLocked(callerApp,
callerApp != null ? callerApp.info.packageName : null, callingFeatureId,
intent, resolvedType, resultTo, resultCode, resultData, resultExtras,
- requiredPermissions, excludedPermissions, appOp, bOptions, serialized,
- sticky, callingPid, callingUid, callingUid, callingPid, userId);
+ requiredPermissions, excludedPermissions, excludedPackages, appOp, bOptions,
+ serialized, sticky, callingPid, callingUid, callingUid, callingPid, userId);
} finally {
Binder.restoreCallingIdentity(origId);
}
@@ -13610,7 +13614,7 @@
try {
return broadcastIntentLocked(null, packageName, featureId, intent, resolvedType,
resultTo, resultCode, resultData, resultExtras, requiredPermissions, null,
- OP_NONE, bOptions, serialized, sticky, -1, uid, realCallingUid,
+ null, OP_NONE, bOptions, serialized, sticky, -1, uid, realCallingUid,
realCallingPid, userId, allowBackgroundActivityStarts,
backgroundActivityStartsToken,
null /* broadcastAllowList */);
@@ -15823,10 +15827,11 @@
return ActivityManagerService.this.broadcastIntentLocked(null /*callerApp*/,
null /*callerPackage*/, null /*callingFeatureId*/, intent,
null /*resolvedType*/, resultTo, 0 /*resultCode*/, null /*resultData*/,
- null /*resultExtras*/, requiredPermissions, null, AppOpsManager.OP_NONE,
- bOptions /*options*/, serialized, false /*sticky*/, callingPid,
- callingUid, callingUid, callingPid, userId,
- false /*allowBackgroundStarts*/,
+ null /*resultExtras*/, requiredPermissions,
+ null /*excludedPermissions*/, null /*excludedPackages*/,
+ AppOpsManager.OP_NONE, bOptions /*options*/, serialized,
+ false /*sticky*/, callingPid, callingUid, callingUid, callingPid,
+ userId, false /*allowBackgroundStarts*/,
null /*tokenNeededForBackgroundActivityStarts*/, appIdAllowList);
} finally {
Binder.restoreCallingIdentity(origId);
@@ -15948,7 +15953,7 @@
| Intent.FLAG_RECEIVER_FOREGROUND
| Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS);
broadcastIntentLocked(null, null, null, intent, null, null, 0, null, null, null,
- null, OP_NONE, null, false, false, MY_PID, SYSTEM_UID,
+ null, null, OP_NONE, null, false, false, MY_PID, SYSTEM_UID,
Binder.getCallingUid(), Binder.getCallingPid(), UserHandle.USER_ALL);
if ((changes & ActivityInfo.CONFIG_LOCALE) != 0) {
intent = new Intent(Intent.ACTION_LOCALE_CHANGED);
@@ -15963,8 +15968,8 @@
TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
PowerExemptionManager.REASON_LOCALE_CHANGED, "");
broadcastIntentLocked(null, null, null, intent, null, null, 0, null, null, null,
- null, OP_NONE, bOptions.toBundle(), false, false, MY_PID, SYSTEM_UID,
- Binder.getCallingUid(), Binder.getCallingPid(),
+ null, null, OP_NONE, bOptions.toBundle(), false, false, MY_PID,
+ SYSTEM_UID, Binder.getCallingUid(), Binder.getCallingPid(),
UserHandle.USER_ALL);
}
@@ -15979,8 +15984,9 @@
String[] permissions =
new String[] { android.Manifest.permission.INSTALL_PACKAGES };
broadcastIntentLocked(null, null, null, intent, null, null, 0, null, null,
- permissions, null, OP_NONE, null, false, false, MY_PID, SYSTEM_UID,
- Binder.getCallingUid(), Binder.getCallingPid(), UserHandle.USER_ALL);
+ permissions, null, null, OP_NONE, null, false, false, MY_PID,
+ SYSTEM_UID, Binder.getCallingUid(), Binder.getCallingPid(),
+ UserHandle.USER_ALL);
}
}
}
@@ -16004,8 +16010,8 @@
}
broadcastIntentLocked(null, null, null, intent, null, null, 0, null, null, null,
- null, OP_NONE, null, false, false, -1, SYSTEM_UID, Binder.getCallingUid(),
- Binder.getCallingPid(), UserHandle.USER_ALL);
+ null, null, OP_NONE, null, false, false, -1, SYSTEM_UID,
+ Binder.getCallingUid(), Binder.getCallingPid(), UserHandle.USER_ALL);
}
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index 685d606..9ab9b24 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -763,8 +763,8 @@
pw.flush();
Bundle bundle = mBroadcastOptions == null ? null : mBroadcastOptions.toBundle();
mInterface.broadcastIntentWithFeature(null, null, intent, null, receiver, 0, null, null,
- requiredPermissions, null, android.app.AppOpsManager.OP_NONE, bundle, true, false,
- mUserId);
+ requiredPermissions, null, null, android.app.AppOpsManager.OP_NONE, bundle, true,
+ false, mUserId);
if (!mAsync) {
receiver.waitForFinish();
}
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index 503b3a9..2383b65 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -60,6 +60,7 @@
import android.util.TimeUtils;
import android.util.proto.ProtoOutputStream;
+import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FrameworkStatsLog;
import java.io.FileDescriptor;
@@ -758,6 +759,22 @@
skip = true;
}
}
+
+ // Check that the receiver does *not* belong to any of the excluded packages
+ if (!skip && r.excludedPackages != null && r.excludedPackages.length > 0) {
+ if (ArrayUtils.contains(r.excludedPackages, filter.packageName)) {
+ Slog.w(TAG, "Skipping delivery of excluded package "
+ + r.intent.toString()
+ + " to " + filter.receiverList.app
+ + " (pid=" + filter.receiverList.pid
+ + ", uid=" + filter.receiverList.uid + ")"
+ + " excludes package " + filter.packageName
+ + " due to sender " + r.callerPackage
+ + " (uid " + r.callingUid + ")");
+ skip = true;
+ }
+ }
+
// If the broadcast also requires an app op check that as well.
if (!skip && r.appOp != AppOpsManager.OP_NONE
&& mService.getAppOpsManager().noteOpNoThrow(r.appOp,
@@ -1586,6 +1603,19 @@
}
}
+ // Check that the receiver does *not* belong to any of the excluded packages
+ if (!skip && r.excludedPackages != null && r.excludedPackages.length > 0) {
+ if (ArrayUtils.contains(r.excludedPackages, component.getPackageName())) {
+ Slog.w(TAG, "Skipping delivery of excluded package "
+ + r.intent + " to "
+ + component.flattenToShortString()
+ + " excludes package " + component.getPackageName()
+ + " due to sender " + r.callerPackage
+ + " (uid " + r.callingUid + ")");
+ skip = true;
+ }
+ }
+
if (!skip && info.activityInfo.applicationInfo.uid != Process.SYSTEM_UID &&
r.requiredPermissions != null && r.requiredPermissions.length > 0) {
for (int i = 0; i < r.requiredPermissions.length; i++) {
diff --git a/services/core/java/com/android/server/am/BroadcastRecord.java b/services/core/java/com/android/server/am/BroadcastRecord.java
index 8015596..84a9482 100644
--- a/services/core/java/com/android/server/am/BroadcastRecord.java
+++ b/services/core/java/com/android/server/am/BroadcastRecord.java
@@ -63,6 +63,7 @@
final String resolvedType; // the resolved data type
final String[] requiredPermissions; // permissions the caller has required
final String[] excludedPermissions; // permissions to exclude
+ final String[] excludedPackages; // packages to exclude
final int appOp; // an app op that is associated with this broadcast
final BroadcastOptions options; // BroadcastOptions supplied by caller
final List receivers; // contains BroadcastFilter and ResolveInfo
@@ -147,6 +148,10 @@
pw.print(prefix); pw.print("excludedPermissions=");
pw.print(Arrays.toString(excludedPermissions));
}
+ if (excludedPackages != null && excludedPackages.length > 0) {
+ pw.print(prefix); pw.print("excludedPackages=");
+ pw.print(Arrays.toString(excludedPackages));
+ }
if (options != null) {
pw.print(prefix); pw.print("options="); pw.println(options.toBundle());
}
@@ -245,7 +250,8 @@
Intent _intent, ProcessRecord _callerApp, String _callerPackage,
@Nullable String _callerFeatureId, int _callingPid, int _callingUid,
boolean _callerInstantApp, String _resolvedType,
- String[] _requiredPermissions, String[] _excludedPermissions, int _appOp,
+ String[] _requiredPermissions, String[] _excludedPermissions,
+ String[] _excludedPackages, int _appOp,
BroadcastOptions _options, List _receivers, IIntentReceiver _resultTo, int _resultCode,
String _resultData, Bundle _resultExtras, boolean _serialized, boolean _sticky,
boolean _initialSticky, int _userId, boolean allowBackgroundActivityStarts,
@@ -265,6 +271,7 @@
resolvedType = _resolvedType;
requiredPermissions = _requiredPermissions;
excludedPermissions = _excludedPermissions;
+ excludedPackages = _excludedPackages;
appOp = _appOp;
options = _options;
receivers = _receivers;
@@ -306,6 +313,7 @@
resolvedType = from.resolvedType;
requiredPermissions = from.requiredPermissions;
excludedPermissions = from.excludedPermissions;
+ excludedPackages = from.excludedPackages;
appOp = from.appOp;
options = from.options;
receivers = from.receivers;
@@ -363,9 +371,10 @@
// build a new BroadcastRecord around that single-target list
BroadcastRecord split = new BroadcastRecord(queue, intent, callerApp, callerPackage,
callerFeatureId, callingPid, callingUid, callerInstantApp, resolvedType,
- requiredPermissions, excludedPermissions, appOp, options, splitReceivers, resultTo,
- resultCode, resultData, resultExtras, ordered, sticky, initialSticky, userId,
- allowBackgroundActivityStarts, mBackgroundActivityStartsToken, timeoutExempt);
+ requiredPermissions, excludedPermissions, excludedPackages, appOp, options,
+ splitReceivers, resultTo, resultCode, resultData, resultExtras, ordered, sticky,
+ initialSticky, userId, allowBackgroundActivityStarts,
+ mBackgroundActivityStartsToken, timeoutExempt);
split.splitToken = this.splitToken;
return split;
diff --git a/services/core/java/com/android/server/am/PreBootBroadcaster.java b/services/core/java/com/android/server/am/PreBootBroadcaster.java
index 7562098..35f91ba 100644
--- a/services/core/java/com/android/server/am/PreBootBroadcaster.java
+++ b/services/core/java/com/android/server/am/PreBootBroadcaster.java
@@ -124,7 +124,7 @@
REASON_PRE_BOOT_COMPLETED, "");
synchronized (mService) {
mService.broadcastIntentLocked(null, null, null, mIntent, null, this, 0, null, null,
- null, null, AppOpsManager.OP_NONE, bOptions.toBundle(), true,
+ null, null, null, AppOpsManager.OP_NONE, bOptions.toBundle(), true,
false, ActivityManagerService.MY_PID,
Process.SYSTEM_UID, Binder.getCallingUid(), Binder.getCallingPid(), mUserId);
}
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index ba3e1fb..e9f668f 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -2937,8 +2937,8 @@
synchronized (mService) {
return mService.broadcastIntentLocked(null, null, null, intent, resolvedType,
resultTo, resultCode, resultData, resultExtras, requiredPermissions, null,
- appOp, bOptions, ordered, sticky, callingPid, callingUid, realCallingUid,
- realCallingPid, userId);
+ null, appOp, bOptions, ordered, sticky, callingPid, callingUid,
+ realCallingUid, realCallingPid, userId);
}
}
diff --git a/services/core/java/com/android/server/apphibernation/AppHibernationService.java b/services/core/java/com/android/server/apphibernation/AppHibernationService.java
index db2ecc5..b2e0b34 100644
--- a/services/core/java/com/android/server/apphibernation/AppHibernationService.java
+++ b/services/core/java/com/android/server/apphibernation/AppHibernationService.java
@@ -418,6 +418,7 @@
null /* resultExtras */,
requiredPermissions,
null /* excludedPermissions */,
+ null /* excludedPackages */,
OP_NONE,
null /* bOptions */,
false /* serialized */,
@@ -436,6 +437,7 @@
null /* resultExtras */,
requiredPermissions,
null /* excludedPermissions */,
+ null /* excludedPackages */,
OP_NONE,
null /* bOptions */,
false /* serialized */,
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 6d29c37..3808e0c 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -3242,7 +3242,7 @@
return AppOpsManager.MODE_IGNORED;
}
synchronized (this) {
- if (isOpRestrictedLocked(uid, code, packageName, attributionTag, pvr.bypass)) {
+ if (isOpRestrictedLocked(uid, code, packageName, attributionTag, pvr.bypass, true)) {
return AppOpsManager.MODE_IGNORED;
}
code = AppOpsManager.opToSwitch(code);
@@ -3459,7 +3459,7 @@
final int switchCode = AppOpsManager.opToSwitch(code);
final UidState uidState = ops.uidState;
- if (isOpRestrictedLocked(uid, code, packageName, attributionTag, pvr.bypass)) {
+ if (isOpRestrictedLocked(uid, code, packageName, attributionTag, pvr.bypass, false)) {
attributedOp.rejected(uidState.state, flags);
scheduleOpNotedIfNeededLocked(code, uid, packageName, attributionTag, flags,
AppOpsManager.MODE_IGNORED);
@@ -3973,7 +3973,8 @@
final Op op = getOpLocked(ops, code, uid, true);
final AttributedOp attributedOp = op.getOrCreateAttribution(op, attributionTag);
final UidState uidState = ops.uidState;
- isRestricted = isOpRestrictedLocked(uid, code, packageName, attributionTag, pvr.bypass);
+ isRestricted = isOpRestrictedLocked(uid, code, packageName, attributionTag, pvr.bypass,
+ false);
final int switchCode = AppOpsManager.opToSwitch(code);
// If there is a non-default per UID policy (we set UID op mode only if
// non-default) it takes over, otherwise use the per package policy.
@@ -4502,8 +4503,9 @@
* @return The restriction matching the package
*/
private RestrictionBypass getBypassforPackage(@NonNull AndroidPackage pkg) {
- return new RestrictionBypass(pkg.isPrivileged(), mContext.checkPermission(
- android.Manifest.permission.EXEMPT_FROM_AUDIO_RECORD_RESTRICTIONS, -1, pkg.getUid())
+ return new RestrictionBypass(pkg.getUid() == Process.SYSTEM_UID, pkg.isPrivileged(),
+ mContext.checkPermission(android.Manifest.permission
+ .EXEMPT_FROM_AUDIO_RECORD_RESTRICTIONS, -1, pkg.getUid())
== PackageManager.PERMISSION_GRANTED);
}
@@ -4763,7 +4765,7 @@
}
private boolean isOpRestrictedLocked(int uid, int code, String packageName,
- String attributionTag, @Nullable RestrictionBypass appBypass) {
+ String attributionTag, @Nullable RestrictionBypass appBypass, boolean isCheckOp) {
int restrictionSetCount = mOpGlobalRestrictions.size();
for (int i = 0; i < restrictionSetCount; i++) {
@@ -4780,11 +4782,15 @@
// For each client, check that the given op is not restricted, or that the given
// package is exempt from the restriction.
ClientUserRestrictionState restrictionState = mOpUserRestrictions.valueAt(i);
- if (restrictionState.hasRestriction(code, packageName, attributionTag, userHandle)) {
+ if (restrictionState.hasRestriction(code, packageName, attributionTag, userHandle,
+ isCheckOp)) {
RestrictionBypass opBypass = opAllowSystemBypassRestriction(code);
if (opBypass != null) {
// If we are the system, bypass user restrictions for certain codes
synchronized (this) {
+ if (opBypass.isSystemUid && appBypass != null && appBypass.isSystemUid) {
+ return false;
+ }
if (opBypass.isPrivileged && appBypass != null && appBypass.isPrivileged) {
return false;
}
@@ -7137,7 +7143,7 @@
}
public boolean hasRestriction(int restriction, String packageName, String attributionTag,
- int userId) {
+ int userId, boolean isCheckOp) {
if (perUserRestrictions == null) {
return false;
}
@@ -7156,6 +7162,9 @@
return true;
}
+ if (isCheckOp) {
+ return !perUserExclusions.includes(packageName);
+ }
return !perUserExclusions.contains(packageName, attributionTag);
}
@@ -7322,7 +7331,8 @@
int numRestrictions = mOpUserRestrictions.size();
for (int i = 0; i < numRestrictions; i++) {
if (mOpUserRestrictions.valueAt(i)
- .hasRestriction(code, pkg, attributionTag, user.getIdentifier())) {
+ .hasRestriction(code, pkg, attributionTag, user.getIdentifier(),
+ false)) {
number++;
}
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
index 6f38ed0..f20c08f 100644
--- a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
@@ -117,7 +117,7 @@
mIsStrongBiometric = isStrongBiometric;
mOperationId = operationId;
mRequireConfirmation = requireConfirmation;
- mActivityTaskManager = ActivityTaskManager.getInstance();
+ mActivityTaskManager = getActivityTaskManager();
mBiometricManager = context.getSystemService(BiometricManager.class);
mTaskStackListener = taskStackListener;
mLockoutTracker = lockoutTracker;
@@ -145,6 +145,10 @@
return mStartTimeMs;
}
+ protected ActivityTaskManager getActivityTaskManager() {
+ return ActivityTaskManager.getInstance();
+ }
+
@Override
public void binderDied() {
final boolean clearListener = !isBiometricPrompt();
@@ -317,45 +321,50 @@
sendCancelOnly(listener);
}
});
- } else {
- // Allow system-defined limit of number of attempts before giving up
- final @LockoutTracker.LockoutMode int lockoutMode =
- handleFailedAttempt(getTargetUserId());
- if (lockoutMode != LockoutTracker.LOCKOUT_NONE) {
- mAlreadyDone = true;
+ } else { // not authenticated
+ if (isBackgroundAuth) {
+ Slog.e(TAG, "cancelling due to background auth");
+ cancel();
+ } else {
+ // Allow system-defined limit of number of attempts before giving up
+ final @LockoutTracker.LockoutMode int lockoutMode =
+ handleFailedAttempt(getTargetUserId());
+ if (lockoutMode != LockoutTracker.LOCKOUT_NONE) {
+ mAlreadyDone = true;
+ }
+
+ final CoexCoordinator coordinator = CoexCoordinator.getInstance();
+ coordinator.onAuthenticationRejected(SystemClock.uptimeMillis(), this, lockoutMode,
+ new CoexCoordinator.Callback() {
+ @Override
+ public void sendAuthenticationResult(boolean addAuthTokenIfStrong) {
+ if (listener != null) {
+ try {
+ listener.onAuthenticationFailed(getSensorId());
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Unable to notify listener", e);
+ }
+ }
+ }
+
+ @Override
+ public void sendHapticFeedback() {
+ if (listener != null && mShouldVibrate) {
+ vibrateError();
+ }
+ }
+
+ @Override
+ public void handleLifecycleAfterAuth() {
+ AuthenticationClient.this.handleLifecycleAfterAuth(false /* authenticated */);
+ }
+
+ @Override
+ public void sendAuthenticationCanceled() {
+ sendCancelOnly(listener);
+ }
+ });
}
-
- final CoexCoordinator coordinator = CoexCoordinator.getInstance();
- coordinator.onAuthenticationRejected(SystemClock.uptimeMillis(), this, lockoutMode,
- new CoexCoordinator.Callback() {
- @Override
- public void sendAuthenticationResult(boolean addAuthTokenIfStrong) {
- if (listener != null) {
- try {
- listener.onAuthenticationFailed(getSensorId());
- } catch (RemoteException e) {
- Slog.e(TAG, "Unable to notify listener", e);
- }
- }
- }
-
- @Override
- public void sendHapticFeedback() {
- if (listener != null && mShouldVibrate) {
- vibrateError();
- }
- }
-
- @Override
- public void handleLifecycleAfterAuth() {
- AuthenticationClient.this.handleLifecycleAfterAuth(false /* authenticated */);
- }
-
- @Override
- public void sendAuthenticationCanceled() {
- sendCancelOnly(listener);
- }
- });
}
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
index 183fabd..2b2e0a0 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
@@ -297,11 +297,11 @@
provider.second.getSensorProperties(sensorId);
if (!isKeyguard && !Utils.isSettings(getContext(), opPackageName)
&& sensorProps != null && sensorProps.isAnyUdfpsType()) {
- identity = Binder.clearCallingIdentity();
try {
- authenticateWithPrompt(operationId, sensorProps, userId, receiver);
- } finally {
- Binder.restoreCallingIdentity(identity);
+ authenticateWithPrompt(operationId, sensorProps, userId, receiver,
+ opPackageName);
+ } catch (PackageManager.NameNotFoundException e) {
+ Slog.e(TAG, "Invalid package", e);
}
} else {
provider.second.scheduleAuthenticate(provider.first, token, operationId, userId,
@@ -314,12 +314,15 @@
final long operationId,
@NonNull final FingerprintSensorPropertiesInternal props,
final int userId,
- final IFingerprintServiceReceiver receiver) {
+ final IFingerprintServiceReceiver receiver,
+ final String opPackageName) throws PackageManager.NameNotFoundException {
final Context context = getUiContext();
+ final Context promptContext = context.createPackageContextAsUser(
+ opPackageName, 0 /* flags */, UserHandle.getUserHandleForUid(userId));
final Executor executor = context.getMainExecutor();
- final BiometricPrompt biometricPrompt = new BiometricPrompt.Builder(context)
+ final BiometricPrompt biometricPrompt = new BiometricPrompt.Builder(promptContext)
.setTitle(context.getString(R.string.biometric_dialog_default_title))
.setSubtitle(context.getString(R.string.fingerprint_dialog_default_subtitle))
.setNegativeButton(
@@ -333,8 +336,7 @@
Slog.e(TAG, "Remote exception in negative button onClick()", e);
}
})
- .setAllowedSensorIds(new ArrayList<>(
- Collections.singletonList(props.sensorId)))
+ .setIsForLegacyFingerprintManager(props.sensorId)
.build();
final BiometricPrompt.AuthenticationCallback promptCallback =
@@ -387,8 +389,8 @@
}
};
- biometricPrompt.authenticateUserForOperation(
- new CancellationSignal(), executor, promptCallback, userId, operationId);
+ biometricPrompt.authenticateForOperation(
+ new CancellationSignal(), executor, promptCallback, operationId);
}
@Override
diff --git a/services/core/java/com/android/server/connectivity/PacProxyService.java b/services/core/java/com/android/server/connectivity/PacProxyService.java
index 0070339..38b386f 100644
--- a/services/core/java/com/android/server/connectivity/PacProxyService.java
+++ b/services/core/java/com/android/server/connectivity/PacProxyService.java
@@ -44,6 +44,7 @@
import android.os.SystemProperties;
import android.provider.Settings;
import android.util.Log;
+import android.webkit.URLUtil;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.TrafficStatsConstants;
@@ -232,8 +233,22 @@
* @throws IOException if the URL is malformed, or the PAC file is too big.
*/
private static String get(Uri pacUri) throws IOException {
- URL url = new URL(pacUri.toString());
- URLConnection urlConnection = url.openConnection(java.net.Proxy.NO_PROXY);
+ if (!URLUtil.isValidUrl(pacUri.toString())) {
+ throw new IOException("Malformed URL:" + pacUri);
+ }
+
+ final URL url = new URL(pacUri.toString());
+ URLConnection urlConnection;
+ try {
+ urlConnection = url.openConnection(java.net.Proxy.NO_PROXY);
+ // Catch the possible exceptions and rethrow as IOException to not to crash the system
+ // for illegal input.
+ } catch (IllegalArgumentException e) {
+ throw new IOException("Incorrect proxy type for " + pacUri);
+ } catch (UnsupportedOperationException e) {
+ throw new IOException("Unsupported URL connection type for " + pacUri);
+ }
+
long contentLength = -1;
try {
contentLength = Long.parseLong(urlConnection.getHeaderField("Content-Length"));
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index 3762cca..637af42 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -2242,6 +2242,13 @@
"usepeerdns", "idle", "1800", "mtu", "1270", "mru", "1270",
(profile.mppe ? "+mppe" : "nomppe"),
};
+ if (profile.mppe) {
+ // Disallow PAP authentication when MPPE is requested, as MPPE cannot work
+ // with PAP anyway, and users may not expect PAP (plain text) to be used when
+ // MPPE was requested.
+ mtpd = Arrays.copyOf(mtpd, mtpd.length + 1);
+ mtpd[mtpd.length - 1] = "-pap";
+ }
break;
case VpnProfile.TYPE_L2TP_IPSEC_PSK:
case VpnProfile.TYPE_L2TP_IPSEC_RSA:
@@ -2620,6 +2627,9 @@
return; // VPN has been shut down.
}
+ // Clear mInterface to prevent Ikev2VpnRunner being cleared when
+ // interfaceRemoved() is called.
+ mInterface = null;
// Without MOBIKE, we have no way to seamlessly migrate. Close on old
// (non-default) network, and start the new one.
resetIkeState();
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 3e52f5e..05c428e 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -124,6 +124,7 @@
import android.util.PrintWriterPrinter;
import android.util.Printer;
import android.util.Slog;
+import android.util.SparseBooleanArray;
import android.util.imetracing.ImeTracing;
import android.util.proto.ProtoOutputStream;
import android.view.IWindowManager;
@@ -300,6 +301,8 @@
final InputMethodSettings mSettings;
final SettingsObserver mSettingsObserver;
final IWindowManager mIWindowManager;
+ private final SparseBooleanArray mLoggedDeniedGetInputMethodWindowVisibleHeightForUid =
+ new SparseBooleanArray(0);
final WindowManagerInternal mWindowManagerInternal;
final PackageManagerInternal mPackageManagerInternal;
final InputManagerInternal mInputManagerInternal;
@@ -1334,6 +1337,13 @@
clearPackageChangeState();
}
+ @Override
+ public void onUidRemoved(int uid) {
+ synchronized (mMethodMap) {
+ mLoggedDeniedGetInputMethodWindowVisibleHeightForUid.delete(uid);
+ }
+ }
+
private void clearPackageChangeState() {
// No need to lock them because we access these fields only on getRegisteredHandler().
mChangedPackages.clear();
@@ -3061,21 +3071,8 @@
}
final long ident = Binder.clearCallingIdentity();
try {
- if (mCurClient == null || client == null
- || mCurClient.client.asBinder() != client.asBinder()) {
- // We need to check if this is the current client with
- // focus in the window manager, to allow this call to
- // be made before input is started in it.
- final ClientState cs = mClients.get(client.asBinder());
- if (cs == null) {
- throw new IllegalArgumentException(
- "unknown client " + client.asBinder());
- }
- if (!mWindowManagerInternal.isInputMethodClientFocus(cs.uid, cs.pid,
- cs.selfReportedDisplayId)) {
- Slog.w(TAG, "Ignoring showSoftInput of uid " + uid + ": " + client);
- return false;
- }
+ if (!canInteractWithImeLocked(uid, client, "showSoftInput")) {
+ return false;
}
if (DEBUG) Slog.v(TAG, "Client requesting input be shown");
return showCurrentInputLocked(windowToken, flags, resultReceiver, reason);
@@ -3900,9 +3897,46 @@
* @return {@link WindowManagerInternal#getInputMethodWindowVisibleHeight(int)}
*/
@Override
- public int getInputMethodWindowVisibleHeight() {
- // TODO(yukawa): Should we verify the display ID?
- return mWindowManagerInternal.getInputMethodWindowVisibleHeight(mCurTokenDisplayId);
+ @Deprecated
+ public int getInputMethodWindowVisibleHeight(@NonNull IInputMethodClient client) {
+ int callingUid = Binder.getCallingUid();
+ return Binder.withCleanCallingIdentity(() -> {
+ final int curTokenDisplayId;
+ synchronized (mMethodMap) {
+ if (!canInteractWithImeLocked(callingUid, client,
+ "getInputMethodWindowVisibleHeight")) {
+ if (!mLoggedDeniedGetInputMethodWindowVisibleHeightForUid.get(callingUid)) {
+ EventLog.writeEvent(0x534e4554, "204906124", callingUid, "");
+ mLoggedDeniedGetInputMethodWindowVisibleHeightForUid.put(callingUid, true);
+ }
+ return 0;
+ }
+ // This should probably use the caller's display id, but because this is unsupported
+ // and maintained only for compatibility, there's no point in fixing it.
+ curTokenDisplayId = mCurTokenDisplayId;
+ }
+ return mWindowManagerInternal.getInputMethodWindowVisibleHeight(curTokenDisplayId);
+ });
+ }
+
+ private boolean canInteractWithImeLocked(int callingUid, IInputMethodClient client,
+ String method) {
+ if (mCurClient == null || client == null
+ || mCurClient.client.asBinder() != client.asBinder()) {
+ // We need to check if this is the current client with
+ // focus in the window manager, to allow this call to
+ // be made before input is started in it.
+ final ClientState cs = mClients.get(client.asBinder());
+ if (cs == null) {
+ throw new IllegalArgumentException("unknown client " + client.asBinder());
+ }
+ if (!mWindowManagerInternal.isInputMethodClientFocus(cs.uid, cs.pid,
+ cs.selfReportedDisplayId)) {
+ Slog.w(TAG, "Ignoring " + method + " of uid " + callingUid + ": " + client);
+ return false;
+ }
+ }
+ return true;
}
@Override
diff --git a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
index aa4fa7c..68c97e1 100644
--- a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
@@ -1803,7 +1803,7 @@
@BinderThread
@Override
- public int getInputMethodWindowVisibleHeight() {
+ public int getInputMethodWindowVisibleHeight(IInputMethodClient client) {
reportNotSupported();
return 0;
}
diff --git a/services/core/java/com/android/server/location/LocationManagerService.java b/services/core/java/com/android/server/location/LocationManagerService.java
index e6210b2..fe5b94a 100644
--- a/services/core/java/com/android/server/location/LocationManagerService.java
+++ b/services/core/java/com/android/server/location/LocationManagerService.java
@@ -17,6 +17,7 @@
package com.android.server.location;
import static android.Manifest.permission.ACCESS_FINE_LOCATION;
+import static android.Manifest.permission.INTERACT_ACROSS_USERS;
import static android.app.compat.CompatChanges.isChangeEnabled;
import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
@@ -39,6 +40,7 @@
import android.Manifest.permission;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
import android.app.ActivityManager;
import android.app.AppOpsManager;
import android.app.PendingIntent;
@@ -1063,8 +1065,10 @@
@Override
public void addProviderRequestListener(IProviderRequestListener listener) {
- for (LocationProviderManager manager : mProviderManagers) {
- manager.addProviderRequestListener(listener);
+ if (mContext.checkCallingOrSelfPermission(INTERACT_ACROSS_USERS) == PERMISSION_GRANTED) {
+ for (LocationProviderManager manager : mProviderManagers) {
+ manager.addProviderRequestListener(listener);
+ }
}
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 33e9af9..2ccf45c 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -245,6 +245,7 @@
import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
+import android.util.SparseBooleanArray;
import android.util.StatsEvent;
import android.util.TypedXmlPullParser;
import android.util.TypedXmlSerializer;
@@ -277,6 +278,7 @@
import com.android.internal.util.Preconditions;
import com.android.internal.util.XmlUtils;
import com.android.internal.util.function.TriPredicate;
+import com.android.internal.widget.LockPatternUtils;
import com.android.server.DeviceIdleInternal;
import com.android.server.EventLogTags;
import com.android.server.IoThread;
@@ -1998,6 +2000,53 @@
private SettingsObserver mSettingsObserver;
protected ZenModeHelper mZenModeHelper;
+ protected class StrongAuthTracker extends LockPatternUtils.StrongAuthTracker {
+
+ SparseBooleanArray mUserInLockDownMode = new SparseBooleanArray();
+ boolean mIsInLockDownMode = false;
+
+ StrongAuthTracker(Context context) {
+ super(context);
+ }
+
+ private boolean containsFlag(int haystack, int needle) {
+ return (haystack & needle) != 0;
+ }
+
+ public boolean isInLockDownMode() {
+ return mIsInLockDownMode;
+ }
+
+ @Override
+ public synchronized void onStrongAuthRequiredChanged(int userId) {
+ boolean userInLockDownModeNext = containsFlag(getStrongAuthForUser(userId),
+ STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN);
+ mUserInLockDownMode.put(userId, userInLockDownModeNext);
+ boolean isInLockDownModeNext = mUserInLockDownMode.indexOfValue(true) != -1;
+
+ if (mIsInLockDownMode == isInLockDownModeNext) {
+ return;
+ }
+
+ if (isInLockDownModeNext) {
+ cancelNotificationsWhenEnterLockDownMode();
+ }
+
+ // When the mIsInLockDownMode is true, both notifyPostedLocked and
+ // notifyRemovedLocked will be dismissed. So we shall call
+ // cancelNotificationsWhenEnterLockDownMode before we set mIsInLockDownMode
+ // as true and call postNotificationsWhenExitLockDownMode after we set
+ // mIsInLockDownMode as false.
+ mIsInLockDownMode = isInLockDownModeNext;
+
+ if (!isInLockDownModeNext) {
+ postNotificationsWhenExitLockDownMode();
+ }
+ }
+ }
+
+ private StrongAuthTracker mStrongAuthTracker;
+
public NotificationManagerService(Context context) {
this(context,
new NotificationRecordLoggerImpl(),
@@ -2021,6 +2070,11 @@
}
@VisibleForTesting
+ void setStrongAuthTracker(StrongAuthTracker strongAuthTracker) {
+ mStrongAuthTracker = strongAuthTracker;
+ }
+
+ @VisibleForTesting
void setKeyguardManager(KeyguardManager keyguardManager) {
mKeyguardManager = keyguardManager;
}
@@ -2207,6 +2261,7 @@
ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE));
mUiHandler = new Handler(UiThread.get().getLooper());
+ mStrongAuthTracker = new StrongAuthTracker(getContext());
String[] extractorNames;
try {
extractorNames = resources.getStringArray(R.array.config_notificationSignalExtractors);
@@ -2689,6 +2744,7 @@
bubbsExtractor.setShortcutHelper(mShortcutHelper);
}
registerNotificationPreferencesPullers();
+ new LockPatternUtils(getContext()).registerStrongAuthTracker(mStrongAuthTracker);
} else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
// This observer will force an update when observe is called, causing us to
// bind to listener services.
@@ -6760,6 +6816,7 @@
@GuardedBy("mNotificationLock")
void snoozeLocked(NotificationRecord r) {
+ final List<NotificationRecord> recordsToSnooze = new ArrayList<>();
if (r.getSbn().isGroup()) {
final List<NotificationRecord> groupNotifications =
findCurrentAndSnoozedGroupNotificationsLocked(
@@ -6768,8 +6825,8 @@
if (r.getNotification().isGroupSummary()) {
// snooze all children
for (int i = 0; i < groupNotifications.size(); i++) {
- if (mKey != groupNotifications.get(i).getKey()) {
- snoozeNotificationLocked(groupNotifications.get(i));
+ if (!mKey.equals(groupNotifications.get(i).getKey())) {
+ recordsToSnooze.add(groupNotifications.get(i));
}
}
} else {
@@ -6779,8 +6836,8 @@
if (groupNotifications.size() == 2) {
// snooze summary and the one child
for (int i = 0; i < groupNotifications.size(); i++) {
- if (mKey != groupNotifications.get(i).getKey()) {
- snoozeNotificationLocked(groupNotifications.get(i));
+ if (!mKey.equals(groupNotifications.get(i).getKey())) {
+ recordsToSnooze.add(groupNotifications.get(i));
}
}
}
@@ -6788,7 +6845,15 @@
}
}
// snooze the notification
- snoozeNotificationLocked(r);
+ recordsToSnooze.add(r);
+
+ if (mSnoozeHelper.canSnooze(recordsToSnooze.size())) {
+ for (int i = 0; i < recordsToSnooze.size(); i++) {
+ snoozeNotificationLocked(recordsToSnooze.get(i));
+ }
+ } else {
+ Log.w(TAG, "Cannot snooze " + r.getKey() + ": too many snoozed notifications");
+ }
}
@@ -9105,6 +9170,29 @@
}
}
+ private void cancelNotificationsWhenEnterLockDownMode() {
+ synchronized (mNotificationLock) {
+ int numNotifications = mNotificationList.size();
+ for (int i = 0; i < numNotifications; i++) {
+ NotificationRecord rec = mNotificationList.get(i);
+ mListeners.notifyRemovedLocked(rec, REASON_CANCEL_ALL,
+ rec.getStats());
+ }
+
+ }
+ }
+
+ private void postNotificationsWhenExitLockDownMode() {
+ synchronized (mNotificationLock) {
+ int numNotifications = mNotificationList.size();
+ for (int i = 0; i < numNotifications; i++) {
+ NotificationRecord rec = mNotificationList.get(i);
+ mListeners.notifyPostedLocked(rec, rec);
+ }
+
+ }
+ }
+
private void updateNotificationPulse() {
synchronized (mNotificationLock) {
updateLightsLocked();
@@ -9340,6 +9428,10 @@
rankings.toArray(new NotificationListenerService.Ranking[0]));
}
+ boolean isInLockDownMode() {
+ return mStrongAuthTracker.isInLockDownMode();
+ }
+
boolean hasCompanionDevice(ManagedServiceInfo info) {
if (mCompanionManager == null) {
mCompanionManager = getCompanionManager();
@@ -10391,8 +10483,12 @@
* targetting <= O_MR1
*/
@GuardedBy("mNotificationLock")
- private void notifyPostedLocked(NotificationRecord r, NotificationRecord old,
+ void notifyPostedLocked(NotificationRecord r, NotificationRecord old,
boolean notifyAllListeners) {
+ if (isInLockDownMode()) {
+ return;
+ }
+
try {
// Lazily initialized snapshots of the notification.
StatusBarNotification sbn = r.getSbn();
@@ -10490,6 +10586,10 @@
@GuardedBy("mNotificationLock")
public void notifyRemovedLocked(NotificationRecord r, int reason,
NotificationStats notificationStats) {
+ if (isInLockDownMode()) {
+ return;
+ }
+
final StatusBarNotification sbn = r.getSbn();
// make a copy in case changes are made to the underlying Notification object
@@ -10535,6 +10635,10 @@
*/
@GuardedBy("mNotificationLock")
public void notifyRankingUpdateLocked(List<NotificationRecord> changedHiddenNotifications) {
+ if (isInLockDownMode()) {
+ return;
+ }
+
boolean isHiddenRankingUpdate = changedHiddenNotifications != null
&& changedHiddenNotifications.size() > 0;
// TODO (b/73052211): if the ranking update changed the notification type,
diff --git a/services/core/java/com/android/server/notification/SnoozeHelper.java b/services/core/java/com/android/server/notification/SnoozeHelper.java
index 4500bbc..2e08a9c 100644
--- a/services/core/java/com/android/server/notification/SnoozeHelper.java
+++ b/services/core/java/com/android/server/notification/SnoozeHelper.java
@@ -62,6 +62,8 @@
public class SnoozeHelper {
public static final int XML_SNOOZED_NOTIFICATION_VERSION = 1;
+ static final int CONCURRENT_SNOOZE_LIMIT = 500;
+
protected static final String XML_TAG_NAME = "snoozed-notifications";
private static final String XML_SNOOZED_NOTIFICATION = "notification";
@@ -134,6 +136,15 @@
}
}
+ protected boolean canSnooze(int numberToSnooze) {
+ synchronized (mLock) {
+ if ((mPackages.size() + numberToSnooze) > CONCURRENT_SNOOZE_LIMIT) {
+ return false;
+ }
+ }
+ return true;
+ }
+
@NonNull
protected Long getSnoozeTimeForUnpostedNotification(int userId, String pkg, String key) {
Long time = null;
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 16a0b7e..5e62496 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -104,6 +104,7 @@
// The amount of time rules instances can exist without their owning app being installed.
private static final int RULE_INSTANCE_GRACE_PERIOD = 1000 * 60 * 60 * 72;
+ static final int RULE_LIMIT_PER_PACKAGE = 100;
// pkg|userId => uid
protected final ArrayMap<String, Integer> mRulesUidCache = new ArrayMap<>();
@@ -325,10 +326,11 @@
int newRuleInstanceCount = getCurrentInstanceCount(automaticZenRule.getOwner())
+ getCurrentInstanceCount(automaticZenRule.getConfigurationActivity())
+ 1;
- if (ruleInstanceLimit > 0 && ruleInstanceLimit < newRuleInstanceCount) {
+ int newPackageRuleCount = getPackageRuleCount(pkg) + 1;
+ if (newPackageRuleCount > RULE_LIMIT_PER_PACKAGE
+ || (ruleInstanceLimit > 0 && ruleInstanceLimit < newRuleInstanceCount)) {
throw new IllegalArgumentException("Rule instance limit exceeded");
}
-
}
ZenModeConfig newConfig;
@@ -506,6 +508,23 @@
return count;
}
+ // Equivalent method to getCurrentInstanceCount, but for all rules associated with a specific
+ // package rather than a condition provider service or activity.
+ private int getPackageRuleCount(String pkg) {
+ if (pkg == null) {
+ return 0;
+ }
+ int count = 0;
+ synchronized (mConfig) {
+ for (ZenRule rule : mConfig.automaticRules.values()) {
+ if (pkg.equals(rule.getPkg())) {
+ count++;
+ }
+ }
+ }
+ return count;
+ }
+
public boolean canManageAutomaticZenRule(ZenRule rule) {
final int callingUid = Binder.getCallingUid();
if (callingUid == 0 || callingUid == Process.SYSTEM_UID) {
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 2f1fa22..708b212 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -390,7 +390,10 @@
// Their staging dirs will be removed too
PackageInstallerSession root = !session.hasParentSessionId()
? session : mSessions.get(session.getParentSessionId());
- if (!root.isDestroyed()) {
+ if (root == null) {
+ Slog.e(TAG, "freeStageDirs: found an orphaned session: "
+ + session.sessionId + " parent=" + session.getParentSessionId());
+ } else if (!root.isDestroyed()) {
root.abandon();
}
} else {
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index d0e4457..3ddcf17 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -126,6 +126,7 @@
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
+import android.util.EventLog;
import android.util.ExceptionUtils;
import android.util.MathUtils;
import android.util.Slog;
@@ -3097,6 +3098,11 @@
if (mResolvedBaseFile == null) {
mResolvedBaseFile = new File(appInfo.getBaseCodePath());
inheritFileLocked(mResolvedBaseFile);
+ } else if ((params.installFlags & PackageManager.INSTALL_DONT_KILL_APP) != 0) {
+ EventLog.writeEvent(0x534e4554, "219044664");
+
+ // Installing base.apk. Make sure the app is restarted.
+ params.setDontKillApp(false);
}
// Inherit splits if not overridden.
@@ -3743,6 +3749,11 @@
}
@Override
+ public int getInstallFlags() {
+ return params.installFlags;
+ }
+
+ @Override
public DataLoaderParamsParcel getDataLoaderParams() {
mContext.enforceCallingOrSelfPermission(Manifest.permission.USE_INSTALLER_V2, null);
return params.dataLoaderParams != null ? params.dataLoaderParams.getData() : null;
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 7968f8f..f9c40a3 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -15854,7 +15854,7 @@
final BroadcastOptions bOptions = getTemporaryAppAllowlistBroadcastOptions(
REASON_LOCKED_BOOT_COMPLETED);
am.broadcastIntentWithFeature(null, null, lockedBcIntent, null, null, 0, null, null,
- requiredPermissions, null, android.app.AppOpsManager.OP_NONE,
+ requiredPermissions, null, null, android.app.AppOpsManager.OP_NONE,
bOptions.toBundle(), false, false, userId);
// Deliver BOOT_COMPLETED only if user is unlocked
@@ -15865,7 +15865,7 @@
bcIntent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
}
am.broadcastIntentWithFeature(null, null, bcIntent, null, null, 0, null, null,
- requiredPermissions, null, android.app.AppOpsManager.OP_NONE,
+ requiredPermissions, null, null, android.app.AppOpsManager.OP_NONE,
bOptions.toBundle(), false, false, userId);
}
} catch (RemoteException e) {
@@ -22779,7 +22779,7 @@
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
try {
am.broadcastIntentWithFeature(null, null, intent, null, null,
- 0, null, null, null, null, android.app.AppOpsManager.OP_NONE,
+ 0, null, null, null, null, null, android.app.AppOpsManager.OP_NONE,
null, false, false, userId);
} catch (RemoteException e) {
}
@@ -28650,8 +28650,8 @@
};
try {
am.broadcastIntentWithFeature(null, null, intent, null, null, 0, null, null,
- requiredPermissions, null, android.app.AppOpsManager.OP_NONE, null, false,
- false, UserHandle.USER_ALL);
+ requiredPermissions, null, null, android.app.AppOpsManager.OP_NONE, null,
+ false, false, UserHandle.USER_ALL);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/services/core/java/com/android/server/pm/UserDataPreparer.java b/services/core/java/com/android/server/pm/UserDataPreparer.java
index 045a295..95482d7 100644
--- a/services/core/java/com/android/server/pm/UserDataPreparer.java
+++ b/services/core/java/com/android/server/pm/UserDataPreparer.java
@@ -22,6 +22,7 @@
import android.content.pm.UserInfo;
import android.os.Environment;
import android.os.FileUtils;
+import android.os.RecoverySystem;
import android.os.storage.StorageManager;
import android.os.storage.VolumeInfo;
import android.os.SystemProperties;
@@ -115,6 +116,16 @@
// Try one last time; if we fail again we're really in trouble
prepareUserDataLI(volumeUuid, userId, userSerial,
flags | StorageManager.FLAG_STORAGE_DE, false);
+ } else {
+ try {
+ Log.wtf(TAG, "prepareUserData failed for user " + userId, e);
+ if (userId == UserHandle.USER_SYSTEM) {
+ RecoverySystem.rebootPromptAndWipeUserData(mContext,
+ "prepareUserData failed for system user");
+ }
+ } catch (IOException e2) {
+ throw new RuntimeException("error rebooting into recovery", e2);
+ }
}
}
}
diff --git a/services/core/java/com/android/server/pm/UserManagerInternal.java b/services/core/java/com/android/server/pm/UserManagerInternal.java
index eb2de60..0e6d5e5 100644
--- a/services/core/java/com/android/server/pm/UserManagerInternal.java
+++ b/services/core/java/com/android/server/pm/UserManagerInternal.java
@@ -312,4 +312,12 @@
*/
public abstract void setDefaultCrossProfileIntentFilters(
@UserIdInt int parentUserId, @UserIdInt int profileUserId);
+
+ /**
+ * Returns {@code true} if the system should ignore errors when preparing
+ * the storage directories for the user with ID {@code userId}. This will
+ * return {@code false} for all new users; it will only return {@code true}
+ * for users that already existed on-disk from an older version of Android.
+ */
+ public abstract boolean shouldIgnorePrepareStorageErrors(int userId);
}
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index d4feb3a..8334d53 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -203,6 +203,8 @@
private static final String TAG_SEED_ACCOUNT_OPTIONS = "seedAccountOptions";
private static final String TAG_LAST_REQUEST_QUIET_MODE_ENABLED_CALL =
"lastRequestQuietModeEnabledCall";
+ private static final String TAG_IGNORE_PREPARE_STORAGE_ERRORS =
+ "ignorePrepareStorageErrors";
private static final String ATTR_KEY = "key";
private static final String ATTR_VALUE_TYPE = "type";
private static final String ATTR_MULTIPLE = "m";
@@ -312,6 +314,14 @@
private long mLastRequestQuietModeEnabledMillis;
+ /**
+ * {@code true} if the system should ignore errors when preparing the
+ * storage directories for this user. This is {@code false} for all new
+ * users; it will only be {@code true} for users that already existed
+ * on-disk from an older version of Android.
+ */
+ private boolean mIgnorePrepareStorageErrors;
+
void setLastRequestQuietModeEnabledMillis(long millis) {
mLastRequestQuietModeEnabledMillis = millis;
}
@@ -320,6 +330,14 @@
return mLastRequestQuietModeEnabledMillis;
}
+ boolean getIgnorePrepareStorageErrors() {
+ return mIgnorePrepareStorageErrors;
+ }
+
+ void setIgnorePrepareStorageErrors() {
+ mIgnorePrepareStorageErrors = true;
+ }
+
void clearSeedAccountData() {
seedAccountName = null;
seedAccountType = null;
@@ -3176,6 +3194,10 @@
serializer.endTag(/* namespace */ null, TAG_LAST_REQUEST_QUIET_MODE_ENABLED_CALL);
}
+ serializer.startTag(/* namespace */ null, TAG_IGNORE_PREPARE_STORAGE_ERRORS);
+ serializer.text(String.valueOf(userData.getIgnorePrepareStorageErrors()));
+ serializer.endTag(/* namespace */ null, TAG_IGNORE_PREPARE_STORAGE_ERRORS);
+
serializer.endTag(null, TAG_USER);
serializer.endDocument();
@@ -3285,6 +3307,7 @@
Bundle legacyLocalRestrictions = null;
RestrictionsSet localRestrictions = null;
Bundle globalRestrictions = null;
+ boolean ignorePrepareStorageErrors = true; // default is true for old users
final TypedXmlPullParser parser = Xml.resolvePullParser(is);
int type;
@@ -3363,6 +3386,11 @@
if (type == XmlPullParser.TEXT) {
lastRequestQuietModeEnabledTimestamp = Long.parseLong(parser.getText());
}
+ } else if (TAG_IGNORE_PREPARE_STORAGE_ERRORS.equals(tag)) {
+ type = parser.next();
+ if (type == XmlPullParser.TEXT) {
+ ignorePrepareStorageErrors = Boolean.parseBoolean(parser.getText());
+ }
}
}
}
@@ -3390,6 +3418,9 @@
userData.persistSeedData = persistSeedData;
userData.seedAccountOptions = seedAccountOptions;
userData.setLastRequestQuietModeEnabledMillis(lastRequestQuietModeEnabledTimestamp);
+ if (ignorePrepareStorageErrors) {
+ userData.setIgnorePrepareStorageErrors();
+ }
synchronized (mRestrictionsLock) {
if (baseRestrictions != null) {
@@ -5227,6 +5258,9 @@
pw.println();
}
}
+
+ pw.println(" Ignore errors preparing storage: "
+ + userData.getIgnorePrepareStorageErrors());
}
}
@@ -5716,6 +5750,14 @@
UserManagerService.this.setDefaultCrossProfileIntentFilters(
profileUserId, userTypeDetails, restrictions, parentUserId);
}
+
+ @Override
+ public boolean shouldIgnorePrepareStorageErrors(int userId) {
+ synchronized (mUsersLock) {
+ UserData userData = mUsers.get(userId);
+ return userData != null && userData.getIgnorePrepareStorageErrors();
+ }
+ }
}
/**
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java
index 855a1cc..6679388 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java
@@ -195,6 +195,12 @@
@Override // Binder interface
public void doKeyguardTimeout(Bundle options) {
+ int userId = mKeyguardStateMonitor.getCurrentUser();
+ if (mKeyguardStateMonitor.isSecure(userId)) {
+ // Preemptively inform the cache that the keyguard will soon be showing, as calls to
+ // doKeyguardTimeout are a signal to lock the device as soon as possible.
+ mKeyguardStateMonitor.onShowingStateChanged(true, userId);
+ }
try {
mService.doKeyguardTimeout(options);
} catch (RemoteException e) {
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java b/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
index add0b01..f0f62ed 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
@@ -83,8 +83,14 @@
return mHasLockscreenWallpaper;
}
+ public int getCurrentUser() {
+ return mCurrentUserId;
+ }
+
@Override // Binder interface
- public void onShowingStateChanged(boolean showing) {
+ public void onShowingStateChanged(boolean showing, int userId) {
+ if (userId != mCurrentUserId) return;
+
mIsShowing = showing;
mCallback.onShowingChanged();
diff --git a/services/core/java/com/android/server/slice/SliceManagerService.java b/services/core/java/com/android/server/slice/SliceManagerService.java
index ee0e5ba..e3dcfd0 100644
--- a/services/core/java/com/android/server/slice/SliceManagerService.java
+++ b/services/core/java/com/android/server/slice/SliceManagerService.java
@@ -247,6 +247,8 @@
if (autoGrantPermissions != null && callingPkg != null) {
// Need to own the Uri to call in with permissions to grant.
enforceOwner(callingPkg, uri, userId);
+ // b/208232850: Needs to verify caller before granting slice access
+ verifyCaller(callingPkg);
for (String perm : autoGrantPermissions) {
if (mContext.checkPermission(perm, pid, uid) == PERMISSION_GRANTED) {
int providerUser = ContentProvider.getUserIdFromUri(uri, userId);
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 66351d67..badad36 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -58,8 +58,8 @@
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
-import android.graphics.BitmapRegionDecoder;
import android.graphics.Color;
+import android.graphics.ImageDecoder;
import android.graphics.Rect;
import android.graphics.RectF;
import android.hardware.display.DisplayManager;
@@ -194,6 +194,8 @@
static final String WALLPAPER_LOCK_ORIG = "wallpaper_lock_orig";
static final String WALLPAPER_LOCK_CROP = "wallpaper_lock";
static final String WALLPAPER_INFO = "wallpaper_info.xml";
+ private static final String RECORD_FILE = "decode_record";
+ private static final String RECORD_LOCK_FILE = "decode_lock_record";
// All the various per-user state files we need to be aware of
private static final String[] sPerUserFiles = new String[] {
@@ -660,8 +662,7 @@
}
if (DEBUG) {
- // This is just a quick estimation, may be smaller than it is.
- long estimateSize = options.outWidth * options.outHeight * 4;
+ long estimateSize = (long) options.outWidth * options.outHeight * 4;
Slog.v(TAG, "Null crop of new wallpaper, estimate size="
+ estimateSize + ", success=" + success);
}
@@ -670,9 +671,6 @@
FileOutputStream f = null;
BufferedOutputStream bos = null;
try {
- BitmapRegionDecoder decoder = BitmapRegionDecoder.newInstance(
- wallpaper.wallpaperFile.getAbsolutePath(), false);
-
// This actually downsamples only by powers of two, but that's okay; we do
// a proper scaling blit later. This is to minimize transient RAM use.
// We calculate the largest power-of-two under the actual ratio rather than
@@ -726,8 +724,24 @@
Slog.v(TAG, " maxTextureSize=" + GLHelper.getMaxTextureSize());
}
- Bitmap cropped = decoder.decodeRegion(cropHint, options);
- decoder.recycle();
+ //Create a record file and will delete if ImageDecoder work well.
+ final String recordName =
+ (wallpaper.wallpaperFile.getName().equals(WALLPAPER)
+ ? RECORD_FILE : RECORD_LOCK_FILE);
+ final File record = new File(getWallpaperDir(wallpaper.userId), recordName);
+ record.createNewFile();
+ Slog.v(TAG, "record path =" + record.getPath()
+ + ", record name =" + record.getName());
+
+ final ImageDecoder.Source srcData =
+ ImageDecoder.createSource(wallpaper.wallpaperFile);
+ final int sampleSize = scale;
+ Bitmap cropped = ImageDecoder.decodeBitmap(srcData, (decoder, info, src) -> {
+ decoder.setTargetSampleSize(sampleSize);
+ decoder.setCrop(estimateCrop);
+ });
+
+ record.delete();
if (cropped == null) {
Slog.e(TAG, "Could not decode new wallpaper");
@@ -1778,6 +1792,7 @@
new UserSwitchObserver() {
@Override
public void onUserSwitching(int newUserId, IRemoteCallback reply) {
+ errorCheck(newUserId);
switchUser(newUserId, reply);
}
}, TAG);
@@ -1815,6 +1830,14 @@
@Override
public void onBootPhase(int phase) {
+ // If someone set too large jpg file as wallpaper, system_server may be killed by lmk in
+ // generateCrop(), so we create a file in generateCrop() before ImageDecoder starts working
+ // and delete this file after ImageDecoder finishing. If the specific file exists, that
+ // means ImageDecoder can't handle the original wallpaper file, in order to avoid
+ // system_server restart again and again and rescue party will trigger factory reset,
+ // so we reset default wallpaper in case system_server is trapped into a restart loop.
+ errorCheck(UserHandle.USER_SYSTEM);
+
if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
systemReady();
} else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
@@ -1822,6 +1845,38 @@
}
}
+ private static final HashMap<Integer, String> sWallpaperType = new HashMap<Integer, String>() {
+ {
+ put(FLAG_SYSTEM, RECORD_FILE);
+ put(FLAG_LOCK, RECORD_LOCK_FILE);
+ }
+ };
+
+ private void errorCheck(int userID) {
+ sWallpaperType.forEach((type, filename) -> {
+ final File record = new File(getWallpaperDir(userID), filename);
+ if (record.exists()) {
+ Slog.w(TAG, "User:" + userID + ", wallpaper tyep = " + type
+ + ", wallpaper fail detect!! reset to default wallpaper");
+ clearWallpaperData(userID, type);
+ record.delete();
+ }
+ });
+ }
+
+ private void clearWallpaperData(int userID, int wallpaperType) {
+ final WallpaperData wallpaper = new WallpaperData(userID, getWallpaperDir(userID),
+ (wallpaperType == FLAG_LOCK) ? WALLPAPER_LOCK_ORIG : WALLPAPER,
+ (wallpaperType == FLAG_LOCK) ? WALLPAPER_LOCK_CROP : WALLPAPER_CROP);
+ if (wallpaper.sourceExists()) {
+ wallpaper.wallpaperFile.delete();
+ }
+ if (wallpaper.cropExists()) {
+ wallpaper.cropFile.delete();
+ }
+
+ }
+
@Override
public void onUnlockUser(final int userId) {
TimingsTraceAndSlog t = new TimingsTraceAndSlog(TAG);
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index c2cfe0b..003d659 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -775,6 +775,13 @@
private AppSaturationInfo mLastAppSaturationInfo;
+ private final ActivityRecordInputSink mActivityRecordInputSink;
+
+ // Activities with this uid are allowed to not create an input sink while being in the same
+ // task and directly above this ActivityRecord. This field is updated whenever a new activity
+ // is launched from this ActivityRecord. Touches are always allowed within the same uid.
+ int mAllowedTouchUid;
+
private final ColorDisplayService.ColorTransformController mColorTransformController =
(matrix, translation) -> mWmService.mH.post(() -> {
synchronized (mWmService.mGlobalLock) {
@@ -1720,6 +1727,8 @@
createTime = _createTime;
}
mAtmService.mPackageConfigPersister.updateConfigIfNeeded(this, mUserId, packageName);
+
+ mActivityRecordInputSink = new ActivityRecordInputSink(this, sourceRecord);
}
/**
@@ -3556,6 +3565,7 @@
destroyImmediately("removeImmediately");
}
onRemovedFromDisplay();
+ mActivityRecordInputSink.releaseSurfaceControl();
super.removeImmediately();
}
@@ -6690,6 +6700,9 @@
} else if (!show && mLastSurfaceShowing) {
getSyncTransaction().hide(mSurfaceControl);
}
+ if (show) {
+ mActivityRecordInputSink.applyChangesToSurfaceIfChanged(getSyncTransaction());
+ }
}
if (mThumbnail != null) {
mThumbnail.setShowing(getPendingTransaction(), show);
diff --git a/services/core/java/com/android/server/wm/ActivityRecordInputSink.java b/services/core/java/com/android/server/wm/ActivityRecordInputSink.java
new file mode 100644
index 0000000..95b5cec
--- /dev/null
+++ b/services/core/java/com/android/server/wm/ActivityRecordInputSink.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+import android.os.Process;
+import android.view.InputWindowHandle;
+import android.view.SurfaceControl;
+import android.view.WindowManager;
+
+/**
+ * Creates a InputWindowHandle that catches all touches that would otherwise pass through an
+ * Activity.
+ */
+class ActivityRecordInputSink {
+
+ private final ActivityRecord mActivityRecord;
+ private final String mName;
+
+ private InputWindowHandle mInputWindowHandle;
+ private SurfaceControl mSurfaceControl;
+
+ ActivityRecordInputSink(ActivityRecord activityRecord, ActivityRecord sourceRecord) {
+ mActivityRecord = activityRecord;
+ mName = Integer.toHexString(System.identityHashCode(this)) + " ActivityRecordInputSink "
+ + mActivityRecord.mActivityComponent.flattenToShortString();
+ if (sourceRecord != null) {
+ sourceRecord.mAllowedTouchUid = mActivityRecord.getUid();
+ }
+ }
+
+ public void applyChangesToSurfaceIfChanged(SurfaceControl.Transaction transaction) {
+ boolean windowHandleChanged = updateInputWindowHandle();
+ if (mSurfaceControl == null) {
+ mSurfaceControl = createSurface(transaction);
+ }
+ if (windowHandleChanged) {
+ transaction.setInputWindowInfo(mSurfaceControl, mInputWindowHandle);
+ }
+ }
+
+ private SurfaceControl createSurface(SurfaceControl.Transaction t) {
+ SurfaceControl surfaceControl = mActivityRecord.makeChildSurface(null)
+ .setName(mName)
+ .setHidden(false)
+ .setCallsite("ActivityRecordInputSink.createSurface")
+ .build();
+ // Put layer below all siblings (and the parent surface too)
+ t.setLayer(surfaceControl, Integer.MIN_VALUE);
+ return surfaceControl;
+ }
+
+ private boolean updateInputWindowHandle() {
+ boolean changed = false;
+ if (mInputWindowHandle == null) {
+ mInputWindowHandle = createInputWindowHandle();
+ changed = true;
+ }
+ // Don't block touches from passing through to an activity below us in the same task, if
+ // that activity is either from the same uid or if that activity has launched an activity
+ // in our uid.
+ final ActivityRecord activityBelowInTask =
+ mActivityRecord.getTask().getActivityBelow(mActivityRecord);
+ final boolean allowPassthrough = activityBelowInTask != null && (
+ activityBelowInTask.mAllowedTouchUid == mActivityRecord.getUid()
+ || activityBelowInTask.isUid(mActivityRecord.getUid()));
+ boolean notTouchable = (mInputWindowHandle.layoutParamsFlags
+ & WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE) != 0;
+ if (allowPassthrough || mActivityRecord.isAppTransitioning()) {
+ mInputWindowHandle.layoutParamsFlags |= WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
+ changed |= !notTouchable;
+ } else {
+ mInputWindowHandle.layoutParamsFlags &= ~WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
+ changed |= notTouchable;
+ }
+ return changed;
+ }
+
+ private InputWindowHandle createInputWindowHandle() {
+ InputWindowHandle inputWindowHandle = new InputWindowHandle(null,
+ mActivityRecord.getDisplayId());
+ inputWindowHandle.replaceTouchableRegionWithCrop = true;
+ inputWindowHandle.name = mName;
+ inputWindowHandle.layoutParamsType = WindowManager.LayoutParams.TYPE_INPUT_CONSUMER;
+ inputWindowHandle.ownerUid = Process.myUid();
+ inputWindowHandle.ownerPid = Process.myPid();
+ inputWindowHandle.layoutParamsFlags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+ inputWindowHandle.inputFeatures =
+ WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL;
+ return inputWindowHandle;
+ }
+
+ void releaseSurfaceControl() {
+ if (mSurfaceControl != null) {
+ mSurfaceControl.release();
+ mSurfaceControl = null;
+ }
+ }
+
+}
diff --git a/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java b/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java
index 316c20b..e088161 100644
--- a/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java
+++ b/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java
@@ -93,7 +93,7 @@
// activities are actually behind other fullscreen activities, but still required
// to be visible (such as performing Recents animation).
final boolean resumeTopActivity = mTop != null && !mTop.mLaunchTaskBehind
- && mTask.isTopActivityFocusable()
+ && mTask.canBeResumed(starting)
&& (starting == null || !starting.isDescendantOf(mTask));
mTask.forAllActivities(a -> {
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index bd688a6..01c1989 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -1948,7 +1948,8 @@
try {
if (mTaskSupervisor.realStartActivityLocked(r, app,
- top == r && r.isFocusable() /*andResume*/, true /*checkConfig*/)) {
+ top == r && r.getTask().canBeResumed(r) /*andResume*/,
+ true /*checkConfig*/)) {
mTmpBoolean = true;
}
} catch (RemoteException e) {
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index c0e339f..a88894e 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -4241,6 +4241,17 @@
}
/**
+ * Returns {@code true} is the activity in this Task can be resumed.
+ *
+ * @param starting The currently starting activity or {@code null} if there is none.
+ */
+ boolean canBeResumed(@Nullable ActivityRecord starting) {
+ // No need to resume activity in Task that is not visible.
+ return isTopActivityFocusable()
+ && getVisibility(starting) == TASK_VISIBILITY_VISIBLE;
+ }
+
+ /**
* Returns true if the task should be visible.
*
* @param starting The currently starting activity or null if there is none.
@@ -7015,7 +7026,23 @@
parentLaunchMode == ActivityInfo.LAUNCH_SINGLE_TASK ||
parentLaunchMode == ActivityInfo.LAUNCH_SINGLE_TOP ||
(destIntentFlags & Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
- parent.deliverNewIntentLocked(callingUid, destIntent, destGrants, srec.packageName);
+ boolean abort;
+ try {
+ abort = !mTaskSupervisor.checkStartAnyActivityPermission(destIntent,
+ parent.info, null /* resultWho */, -1 /* requestCode */, srec.getPid(),
+ callingUid, srec.info.packageName, null /* callingFeatureId */,
+ false /* ignoreTargetSecurity */, false /* launchingInTask */, srec.app,
+ null /* resultRecord */, null /* resultRootTask */);
+ } catch (SecurityException e) {
+ abort = true;
+ }
+ if (abort) {
+ android.util.EventLog.writeEvent(0x534e4554, "238605611", callingUid, "");
+ foundParentInTask = false;
+ } else {
+ parent.deliverNewIntentLocked(callingUid, destIntent, destGrants,
+ srec.packageName);
+ }
} else {
try {
ActivityInfo aInfo = AppGlobals.getPackageManager().getActivityInfo(
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index fac9539..b69182f 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2643,6 +2643,10 @@
void finishDrawingWindow(Session session, IWindow client,
@Nullable SurfaceControl.Transaction postDrawTransaction) {
+ if (postDrawTransaction != null) {
+ postDrawTransaction.sanitize();
+ }
+
final long origId = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 5e042ef..3fe294e 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -3537,7 +3537,10 @@
}
// Exclude toast because legacy apps may show toast window by themselves, so the misused
// apps won't always be considered as foreground state.
- if (mAttrs.type >= FIRST_SYSTEM_WINDOW && mAttrs.type != TYPE_TOAST) {
+ // Exclude private presentations as they can only be shown on private virtual displays and
+ // shouldn't be the cause of an app be considered foreground.
+ if (mAttrs.type >= FIRST_SYSTEM_WINDOW && mAttrs.type != TYPE_TOAST
+ && mAttrs.type != TYPE_PRIVATE_PRESENTATION) {
mWmService.mAtmService.mActiveUids.onNonAppSurfaceVisibilityChanged(mOwnerUid, shown);
}
if (mIsImWindow && mWmService.mAccessibilityController != null) {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
index 55ab8c3..10ff244 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
@@ -15,6 +15,7 @@
*/
package com.android.server.devicepolicy;
+import android.accounts.Account;
import android.annotation.NonNull;
import android.annotation.UserIdInt;
import android.app.admin.DevicePolicySafetyChecker;
@@ -58,6 +59,7 @@
* @see {@link SystemService#onUserUnlocking}
*/
abstract void handleUnlockUser(int userId);
+
/**
* To be called by {@link DevicePolicyManagerService#Lifecycle} after a user is being unlocked.
*
@@ -133,6 +135,11 @@
return null;
}
+ public void finalizeWorkProfileProvisioning(
+ UserHandle managedProfileUser, Account migratedAccount) {
+
+ }
+
public void provisionFullyManagedDevice(
FullyManagedDeviceProvisioningParams provisioningParams, String callerPackage) {
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 330e268..dc67d6f 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -26,6 +26,7 @@
import static android.app.admin.DeviceAdminReceiver.ACTION_COMPLIANCE_ACKNOWLEDGEMENT_REQUIRED;
import static android.app.admin.DeviceAdminReceiver.EXTRA_TRANSFER_OWNERSHIP_ADMIN_EXTRAS_BUNDLE;
import static android.app.admin.DevicePolicyManager.ACTION_CHECK_POLICY_COMPLIANCE;
+import static android.app.admin.DevicePolicyManager.ACTION_MANAGED_PROFILE_PROVISIONED;
import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE;
import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE;
import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_USER;
@@ -56,6 +57,7 @@
import static android.app.admin.DevicePolicyManager.DELEGATION_PERMISSION_GRANT;
import static android.app.admin.DevicePolicyManager.DELEGATION_SECURITY_LOGGING;
import static android.app.admin.DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE_PER_USER;
+import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE;
import static android.app.admin.DevicePolicyManager.ID_TYPE_BASE_INFO;
import static android.app.admin.DevicePolicyManager.ID_TYPE_IMEI;
import static android.app.admin.DevicePolicyManager.ID_TYPE_INDIVIDUAL_ATTESTATION;
@@ -10479,6 +10481,35 @@
}
@Override
+ public void finalizeWorkProfileProvisioning(UserHandle managedProfileUser,
+ Account migratedAccount) {
+ Preconditions.checkCallAuthorization(
+ hasCallingOrSelfPermission(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS));
+
+ if (!isManagedProfile(managedProfileUser.getIdentifier())) {
+ throw new IllegalStateException("Given user is not a managed profile");
+ }
+ ComponentName profileOwnerComponent =
+ mOwners.getProfileOwnerComponent(managedProfileUser.getIdentifier());
+ if (profileOwnerComponent == null) {
+ throw new IllegalStateException("There is no profile owner on the given profile");
+ }
+ Intent primaryProfileSuccessIntent = new Intent(ACTION_MANAGED_PROFILE_PROVISIONED);
+ primaryProfileSuccessIntent.setPackage(profileOwnerComponent.getPackageName());
+ primaryProfileSuccessIntent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES
+ | Intent.FLAG_RECEIVER_FOREGROUND);
+ primaryProfileSuccessIntent.putExtra(Intent.EXTRA_USER, managedProfileUser);
+
+ if (migratedAccount != null) {
+ primaryProfileSuccessIntent.putExtra(EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE,
+ migratedAccount);
+ }
+
+ mContext.sendBroadcastAsUser(primaryProfileSuccessIntent,
+ UserHandle.of(getProfileParentId(managedProfileUser.getIdentifier())));
+ }
+
+ @Override
public UserHandle createAndManageUser(ComponentName admin, String name,
ComponentName profileOwner, PersistableBundle adminExtras, int flags) {
Objects.requireNonNull(admin, "admin is null");
diff --git a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
index 2690948..55619bc 100644
--- a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
@@ -36,6 +36,7 @@
import android.accounts.IAccountManagerResponse;
import android.app.AppOpsManager;
import android.app.INotificationManager;
+import android.app.PropertyInvalidatedCache;
import android.app.admin.DevicePolicyManager;
import android.app.admin.DevicePolicyManagerInternal;
import android.content.BroadcastReceiver;
@@ -132,6 +133,8 @@
protected void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
+ PropertyInvalidatedCache.disableForTestMode();
+
when(mMockPackageManager.checkSignatures(anyInt(), anyInt()))
.thenReturn(PackageManager.SIGNATURE_MATCH);
final UserInfo ui = new UserInfo(UserHandle.USER_SYSTEM, "user0", 0);
@@ -248,6 +251,27 @@
}
@SmallTest
+ public void testCheckAddAccountLongName() throws Exception {
+ unlockSystemUser();
+ //test comment
+ String longString = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ + "aaaaa";
+ Account a11 = new Account(longString, AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1);
+
+ mAms.addAccountExplicitly(
+ a11, /* password= */ "p11", /* extras= */ null, /* callerPackage= */ null);
+
+ String[] list = new String[]{AccountManagerServiceTestFixtures.CALLER_PACKAGE};
+ when(mMockPackageManager.getPackagesForUid(anyInt())).thenReturn(list);
+ Account[] accounts = mAms.getAccountsAsUser(null,
+ UserHandle.getCallingUserId(), mContext.getOpPackageName());
+ assertEquals(0, accounts.length);
+ }
+
+
+ @SmallTest
public void testPasswords() throws Exception {
unlockSystemUser();
Account a11 = new Account("account1", AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1);
diff --git a/services/tests/servicestests/src/com/android/server/am/BroadcastRecordTest.java b/services/tests/servicestests/src/com/android/server/am/BroadcastRecordTest.java
index e9b5b62..f44104e 100644
--- a/services/tests/servicestests/src/com/android/server/am/BroadcastRecordTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/BroadcastRecordTest.java
@@ -185,6 +185,7 @@
null /* resolvedType */,
null /* requiredPermissions */,
null /* excludedPermissions */,
+ null /* excludedPackages */,
0 /* appOp */,
null /* options */,
new ArrayList<>(receivers), // Make a copy to not affect the original list.
diff --git a/services/tests/servicestests/src/com/android/server/apphibernation/AppHibernationServiceTest.java b/services/tests/servicestests/src/com/android/server/apphibernation/AppHibernationServiceTest.java
index 5c7a580..2dcd1c1 100644
--- a/services/tests/servicestests/src/com/android/server/apphibernation/AppHibernationServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/apphibernation/AppHibernationServiceTest.java
@@ -294,7 +294,7 @@
ArgumentCaptor<Intent> intentArgumentCaptor = ArgumentCaptor.forClass(Intent.class);
verify(mIActivityManager, times(2)).broadcastIntentWithFeature(any(), any(),
intentArgumentCaptor.capture(), any(), any(), anyInt(), any(), any(), any(), any(),
- anyInt(), any(), anyBoolean(), anyBoolean(), eq(USER_ID_1));
+ any(), anyInt(), any(), anyBoolean(), anyBoolean(), eq(USER_ID_1));
List<Intent> capturedIntents = intentArgumentCaptor.getAllValues();
assertEquals(capturedIntents.get(0).getAction(), Intent.ACTION_LOCKED_BOOT_COMPLETED);
assertEquals(capturedIntents.get(1).getAction(), Intent.ACTION_BOOT_COMPLETED);
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java
index a227cd3..035249e 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java
@@ -70,6 +70,7 @@
import org.junit.After;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
@@ -516,6 +517,7 @@
}
}
+ @Ignore("Causing breakages so ignoring to resolve, b/231667368")
@Test
public void initRecoveryService_alwaysUpdatesCertsWhenTestRootCertIsUsed() throws Exception {
int uid = Binder.getCallingUid();
@@ -539,6 +541,7 @@
testRootCertAlias)).isEqualTo(TestData.getInsecureCertPathForEndpoint2());
}
+ @Ignore("Causing breakages so ignoring to resolve, b/231667368")
@Test
public void initRecoveryService_updatesCertsIndependentlyForDifferentRoots() throws Exception {
int uid = Binder.getCallingUid();
diff --git a/services/tests/uiservicestests/AndroidManifest.xml b/services/tests/uiservicestests/AndroidManifest.xml
index 767857b..e8e3a8f 100644
--- a/services/tests/uiservicestests/AndroidManifest.xml
+++ b/services/tests/uiservicestests/AndroidManifest.xml
@@ -33,6 +33,7 @@
<uses-permission android:name="android.permission.OBSERVE_ROLE_HOLDERS" />
<uses-permission android:name="android.permission.GET_INTENT_SENDER_INTENT"/>
<uses-permission android:name="android.permission.WRITE_DEVICE_CONFIG" />
+ <uses-permission android:name="android.permission.ACCESS_KEYGUARD_SECURE_STORAGE" />
<application android:debuggable="true">
<uses-library android:name="android.test.runner" />
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java
index 50ebffc..313f307 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java
@@ -24,10 +24,12 @@
import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.INotificationManager;
@@ -39,9 +41,10 @@
import android.os.Bundle;
import android.service.notification.NotificationListenerFilter;
import android.service.notification.NotificationListenerService;
+import android.service.notification.NotificationStats;
+import android.service.notification.StatusBarNotification;
import android.util.ArraySet;
import android.util.Pair;
-import android.util.Slog;
import android.util.TypedXmlPullParser;
import android.util.TypedXmlSerializer;
import android.util.Xml;
@@ -52,11 +55,13 @@
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import org.mockito.internal.util.reflection.FieldSetter;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
+import java.util.List;
public class NotificationListenersTest extends UiServiceTestCase {
@@ -355,4 +360,65 @@
.getDisallowedPackages()).isEmpty();
}
+ @Test
+ public void testNotifyPostedLockedInLockdownMode() {
+ NotificationRecord r = mock(NotificationRecord.class);
+ NotificationRecord old = mock(NotificationRecord.class);
+
+ // before the lockdown mode
+ when(mNm.isInLockDownMode()).thenReturn(false);
+ mListeners.notifyPostedLocked(r, old, true);
+ mListeners.notifyPostedLocked(r, old, false);
+ verify(r, atLeast(2)).getSbn();
+
+ // in the lockdown mode
+ reset(r);
+ reset(old);
+ when(mNm.isInLockDownMode()).thenReturn(true);
+ mListeners.notifyPostedLocked(r, old, true);
+ mListeners.notifyPostedLocked(r, old, false);
+ verify(r, never()).getSbn();
+ }
+
+ @Test
+ public void testnotifyRankingUpdateLockedInLockdownMode() {
+ List chn = mock(List.class);
+
+ // before the lockdown mode
+ when(mNm.isInLockDownMode()).thenReturn(false);
+ mListeners.notifyRankingUpdateLocked(chn);
+ verify(chn, atLeast(1)).size();
+
+ // in the lockdown mode
+ reset(chn);
+ when(mNm.isInLockDownMode()).thenReturn(true);
+ mListeners.notifyRankingUpdateLocked(chn);
+ verify(chn, never()).size();
+ }
+
+ @Test
+ public void testNotifyRemovedLockedInLockdownMode() throws NoSuchFieldException {
+ NotificationRecord r = mock(NotificationRecord.class);
+ NotificationStats rs = mock(NotificationStats.class);
+ StatusBarNotification sbn = mock(StatusBarNotification.class);
+ FieldSetter.setField(mNm,
+ NotificationManagerService.class.getDeclaredField("mHandler"),
+ mock(NotificationManagerService.WorkerHandler.class));
+
+ // before the lockdown mode
+ when(mNm.isInLockDownMode()).thenReturn(false);
+ when(r.getSbn()).thenReturn(sbn);
+ mListeners.notifyRemovedLocked(r, 0, rs);
+ mListeners.notifyRemovedLocked(r, 0, rs);
+ verify(r, atLeast(2)).getSbn();
+
+ // in the lockdown mode
+ reset(r);
+ reset(rs);
+ when(mNm.isInLockDownMode()).thenReturn(true);
+ when(r.getSbn()).thenReturn(sbn);
+ mListeners.notifyRemovedLocked(r, 0, rs);
+ mListeners.notifyRemovedLocked(r, 0, rs);
+ verify(r, never()).getSbn();
+ }
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index e8e08bf..3f9a8d2 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -58,9 +58,11 @@
import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_ALERTING;
import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_CONVERSATIONS;
import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_ONGOING;
+import static android.service.notification.NotificationListenerService.REASON_CANCEL_ALL;
import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEGATIVE;
import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEUTRAL;
+import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN;
import static com.android.server.notification.NotificationManagerService.ACTION_DISABLE_NAS;
import static com.android.server.notification.NotificationManagerService.ACTION_ENABLE_NAS;
import static com.android.server.notification.NotificationManagerService.ACTION_LEARNMORE_NAS;
@@ -225,7 +227,6 @@
import java.util.Collections;
import java.util.List;
import java.util.Map;
-import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.function.Consumer;
@@ -411,8 +412,26 @@
interface NotificationAssistantAccessGrantedCallback {
void onGranted(ComponentName assistant, int userId, boolean granted, boolean userSet);
}
+
+ class StrongAuthTrackerFake extends NotificationManagerService.StrongAuthTracker {
+ private int mGetStrongAuthForUserReturnValue = 0;
+ StrongAuthTrackerFake(Context context) {
+ super(context);
+ }
+
+ public void setGetStrongAuthForUserReturnValue(int val) {
+ mGetStrongAuthForUserReturnValue = val;
+ }
+
+ @Override
+ public int getStrongAuthForUser(int userId) {
+ return mGetStrongAuthForUserReturnValue;
+ }
+ }
}
+ TestableNotificationManagerService.StrongAuthTrackerFake mStrongAuthTracker;
+
private class TestableToastCallback extends ITransientNotification.Stub {
@Override
public void show(IBinder windowToken) {
@@ -532,6 +551,9 @@
mService.setAudioManager(mAudioManager);
+ mStrongAuthTracker = mService.new StrongAuthTrackerFake(mContext);
+ mService.setStrongAuthTracker(mStrongAuthTracker);
+
mShortcutHelper = mService.getShortcutHelper();
mShortcutHelper.setLauncherApps(mLauncherApps);
mShortcutHelper.setShortcutServiceInternal(mShortcutServiceInternal);
@@ -2757,19 +2779,80 @@
}
@Test
+ public void testSnoozeRunnable_tooManySnoozed_singleNotification() {
+ final NotificationRecord notification = generateNotificationRecord(
+ mTestNotificationChannel, 1, null, true);
+ mService.addNotification(notification);
+
+ when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true);
+ when(mSnoozeHelper.canSnooze(1)).thenReturn(false);
+
+ NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable =
+ mService.new SnoozeNotificationRunnable(
+ notification.getKey(), 100, null);
+ snoozeNotificationRunnable.run();
+
+ verify(mSnoozeHelper, never()).snooze(any(NotificationRecord.class), anyLong());
+ assertEquals(1, mService.getNotificationRecordCount());
+ }
+
+ @Test
+ public void testSnoozeRunnable_tooManySnoozed_singleGroupChildNotification() {
+ final NotificationRecord notification = generateNotificationRecord(
+ mTestNotificationChannel, 1, "group", true);
+ final NotificationRecord notificationChild = generateNotificationRecord(
+ mTestNotificationChannel, 1, "group", false);
+ mService.addNotification(notification);
+ mService.addNotification(notificationChild);
+
+ when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true);
+ when(mSnoozeHelper.canSnooze(2)).thenReturn(false);
+
+ NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable =
+ mService.new SnoozeNotificationRunnable(
+ notificationChild.getKey(), 100, null);
+ snoozeNotificationRunnable.run();
+
+ verify(mSnoozeHelper, never()).snooze(any(NotificationRecord.class), anyLong());
+ assertEquals(2, mService.getNotificationRecordCount());
+ }
+
+ @Test
+ public void testSnoozeRunnable_tooManySnoozed_summaryNotification() {
+ final NotificationRecord notification = generateNotificationRecord(
+ mTestNotificationChannel, 1, "group", true);
+ final NotificationRecord notificationChild = generateNotificationRecord(
+ mTestNotificationChannel, 12, "group", false);
+ final NotificationRecord notificationChild2 = generateNotificationRecord(
+ mTestNotificationChannel, 13, "group", false);
+ mService.addNotification(notification);
+ mService.addNotification(notificationChild);
+ mService.addNotification(notificationChild2);
+
+ when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true);
+ when(mSnoozeHelper.canSnooze(3)).thenReturn(false);
+
+ NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable =
+ mService.new SnoozeNotificationRunnable(
+ notification.getKey(), 100, null);
+ snoozeNotificationRunnable.run();
+
+ verify(mSnoozeHelper, never()).snooze(any(NotificationRecord.class), anyLong());
+ assertEquals(3, mService.getNotificationRecordCount());
+ }
+
+ @Test
public void testSnoozeRunnable_reSnoozeASingleSnoozedNotification() throws Exception {
final NotificationRecord notification = generateNotificationRecord(
mTestNotificationChannel, 1, null, true);
mService.addNotification(notification);
when(mSnoozeHelper.getNotification(any())).thenReturn(notification);
+ when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true);
NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable =
mService.new SnoozeNotificationRunnable(
notification.getKey(), 100, null);
snoozeNotificationRunnable.run();
- NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable2 =
- mService.new SnoozeNotificationRunnable(
- notification.getKey(), 100, null);
snoozeNotificationRunnable.run();
// snooze twice
@@ -2777,19 +2860,17 @@
}
@Test
- public void testSnoozeRunnable_reSnoozeASnoozedNotificationWithGroupKey() throws Exception {
+ public void testSnoozeRunnable_reSnoozeASnoozedNotificationWithGroupKey() {
final NotificationRecord notification = generateNotificationRecord(
mTestNotificationChannel, 1, "group", true);
mService.addNotification(notification);
when(mSnoozeHelper.getNotification(any())).thenReturn(notification);
+ when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true);
NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable =
mService.new SnoozeNotificationRunnable(
notification.getKey(), 100, null);
snoozeNotificationRunnable.run();
- NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable2 =
- mService.new SnoozeNotificationRunnable(
- notification.getKey(), 100, null);
snoozeNotificationRunnable.run();
// snooze twice
@@ -2807,6 +2888,7 @@
when(mSnoozeHelper.getNotification(any())).thenReturn(notification);
when(mSnoozeHelper.getNotifications(
anyString(), anyString(), anyInt())).thenReturn(new ArrayList<>());
+ when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true);
NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable =
mService.new SnoozeNotificationRunnable(
@@ -2816,8 +2898,8 @@
.thenReturn(new ArrayList<>(Arrays.asList(notification, notification2)));
NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable2 =
mService.new SnoozeNotificationRunnable(
- notification.getKey(), 100, null);
- snoozeNotificationRunnable.run();
+ notification2.getKey(), 100, null);
+ snoozeNotificationRunnable2.run();
// snooze twice
verify(mSnoozeHelper, times(4)).snooze(any(NotificationRecord.class), anyLong());
@@ -2831,6 +2913,7 @@
mTestNotificationChannel, 2, "group", false);
mService.addNotification(grouped);
mService.addNotification(nonGrouped);
+ when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true);
NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable =
mService.new SnoozeNotificationRunnable(
@@ -2860,6 +2943,7 @@
mService.addNotification(parent);
mService.addNotification(child);
mService.addNotification(child2);
+ when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true);
NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable =
mService.new SnoozeNotificationRunnable(
@@ -2881,6 +2965,7 @@
mService.addNotification(parent);
mService.addNotification(child);
mService.addNotification(child2);
+ when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true);
NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable =
mService.new SnoozeNotificationRunnable(
@@ -2906,6 +2991,7 @@
mTestNotificationChannel, 2, "group", false);
mService.addNotification(parent);
mService.addNotification(child);
+ when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true);
NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable =
mService.new SnoozeNotificationRunnable(
@@ -2933,6 +3019,7 @@
final NotificationRecord child = generateNotificationRecord(
mTestNotificationChannel, 2, "group", false);
mService.addNotification(child);
+ when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true);
NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable =
mService.new SnoozeNotificationRunnable(
@@ -8263,4 +8350,44 @@
}
}
}
+
+ @Test
+ public void testStrongAuthTracker_isInLockDownMode() {
+ mStrongAuthTracker.setGetStrongAuthForUserReturnValue(
+ STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN);
+ mStrongAuthTracker.onStrongAuthRequiredChanged(mContext.getUserId());
+ assertTrue(mStrongAuthTracker.isInLockDownMode());
+ mStrongAuthTracker.setGetStrongAuthForUserReturnValue(0);
+ mStrongAuthTracker.onStrongAuthRequiredChanged(mContext.getUserId());
+ assertFalse(mStrongAuthTracker.isInLockDownMode());
+ }
+
+ @Test
+ public void testCancelAndPostNotificationsWhenEnterAndExitLockDownMode() {
+ // post 2 notifications from 2 packages
+ NotificationRecord pkgA = new NotificationRecord(mContext,
+ generateSbn("a", 1000, 9, 0), mTestNotificationChannel);
+ mService.addNotification(pkgA);
+ NotificationRecord pkgB = new NotificationRecord(mContext,
+ generateSbn("b", 1001, 9, 0), mTestNotificationChannel);
+ mService.addNotification(pkgB);
+
+ // when entering the lockdown mode, cancel the 2 notifications.
+ mStrongAuthTracker.setGetStrongAuthForUserReturnValue(
+ STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN);
+ mStrongAuthTracker.onStrongAuthRequiredChanged(mContext.getUserId());
+ assertTrue(mStrongAuthTracker.isInLockDownMode());
+
+ // the notifyRemovedLocked function is called twice due to REASON_LOCKDOWN.
+ ArgumentCaptor<Integer> captor = ArgumentCaptor.forClass(Integer.class);
+ verify(mListeners, times(2)).notifyRemovedLocked(any(), captor.capture(), any());
+ assertEquals(REASON_CANCEL_ALL, captor.getValue().intValue());
+
+ // exit lockdown mode.
+ mStrongAuthTracker.setGetStrongAuthForUserReturnValue(0);
+ mStrongAuthTracker.onStrongAuthRequiredChanged(mContext.getUserId());
+
+ // the notifyPostedLocked function is called twice.
+ verify(mListeners, times(2)).notifyPostedLocked(any(), any());
+ }
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java
index 2ae2ef7..8bead57 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java
@@ -15,6 +15,7 @@
*/
package com.android.server.notification;
+import static com.android.server.notification.SnoozeHelper.CONCURRENT_SNOOZE_LIMIT;
import static com.android.server.notification.SnoozeHelper.EXTRA_KEY;
import static junit.framework.Assert.assertEquals;
@@ -281,6 +282,22 @@
}
@Test
+ public void testSnoozeLimit() {
+ for (int i = 0; i < CONCURRENT_SNOOZE_LIMIT; i++ ) {
+ NotificationRecord r = getNotificationRecord("pkg", i, i+"", UserHandle.SYSTEM);
+
+ assertTrue("cannot snooze record " + i, mSnoozeHelper.canSnooze(1));
+
+ if (i % 2 == 0) {
+ mSnoozeHelper.snooze(r, null);
+ } else {
+ mSnoozeHelper.snooze(r, 9000);
+ }
+ }
+ assertFalse(mSnoozeHelper.canSnooze(1));
+ }
+
+ @Test
public void testCancelByApp() throws Exception {
NotificationRecord r = getNotificationRecord("pkg", 1, "one", UserHandle.SYSTEM);
NotificationRecord r2 = getNotificationRecord("pkg", 2, "two", UserHandle.SYSTEM);
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
index 4410404..c0fb39c 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
@@ -42,6 +42,7 @@
import static com.android.os.AtomsProto.DNDModeProto.ID_FIELD_NUMBER;
import static com.android.os.AtomsProto.DNDModeProto.UID_FIELD_NUMBER;
import static com.android.os.AtomsProto.DNDModeProto.ZEN_MODE_FIELD_NUMBER;
+import static com.android.server.notification.ZenModeHelper.RULE_LIMIT_PER_PACKAGE;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
@@ -1607,6 +1608,66 @@
}
@Test
+ public void testAddAutomaticZenRule_beyondSystemLimit() {
+ for (int i = 0; i < RULE_LIMIT_PER_PACKAGE; i++) {
+ ScheduleInfo si = new ScheduleInfo();
+ si.startHour = i;
+ AutomaticZenRule zenRule = new AutomaticZenRule("name" + i,
+ null,
+ new ComponentName("android", "ScheduleConditionProvider"),
+ ZenModeConfig.toScheduleConditionId(si),
+ new ZenPolicy.Builder().build(),
+ NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
+ // We need the package name to be something that's not "android" so there aren't any
+ // existing rules under that package.
+ String id = mZenModeHelperSpy.addAutomaticZenRule("pkgname", zenRule, "test");
+ assertNotNull(id);
+ }
+ try {
+ AutomaticZenRule zenRule = new AutomaticZenRule("name",
+ null,
+ new ComponentName("android", "ScheduleConditionProvider"),
+ ZenModeConfig.toScheduleConditionId(new ScheduleInfo()),
+ new ZenPolicy.Builder().build(),
+ NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
+ String id = mZenModeHelperSpy.addAutomaticZenRule("pkgname", zenRule, "test");
+ fail("allowed too many rules to be created");
+ } catch (IllegalArgumentException e) {
+ // yay
+ }
+ }
+
+ @Test
+ public void testAddAutomaticZenRule_beyondSystemLimit_differentComponents() {
+ // Make sure the system limit is enforced per-package even with different component provider
+ // names.
+ for (int i = 0; i < RULE_LIMIT_PER_PACKAGE; i++) {
+ ScheduleInfo si = new ScheduleInfo();
+ si.startHour = i;
+ AutomaticZenRule zenRule = new AutomaticZenRule("name" + i,
+ null,
+ new ComponentName("android", "ScheduleConditionProvider" + i),
+ ZenModeConfig.toScheduleConditionId(si),
+ new ZenPolicy.Builder().build(),
+ NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
+ String id = mZenModeHelperSpy.addAutomaticZenRule("pkgname", zenRule, "test");
+ assertNotNull(id);
+ }
+ try {
+ AutomaticZenRule zenRule = new AutomaticZenRule("name",
+ null,
+ new ComponentName("android", "ScheduleConditionProviderFinal"),
+ ZenModeConfig.toScheduleConditionId(new ScheduleInfo()),
+ new ZenPolicy.Builder().build(),
+ NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
+ String id = mZenModeHelperSpy.addAutomaticZenRule("pkgname", zenRule, "test");
+ fail("allowed too many rules to be created");
+ } catch (IllegalArgumentException e) {
+ // yay
+ }
+ }
+
+ @Test
public void testAddAutomaticZenRule_CA() {
AutomaticZenRule zenRule = new AutomaticZenRule("name",
null,
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index 661dcbb..9f31647 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -175,7 +175,11 @@
// Delay for debouncing USB disconnects.
// We often get rapid connect/disconnect events when enabling USB functions,
// which need debouncing.
- private static final int UPDATE_DELAY = 1000;
+ private static final int DEVICE_STATE_UPDATE_DELAY_EXT = 3000;
+ private static final int DEVICE_STATE_UPDATE_DELAY = 1000;
+
+ // Delay for debouncing USB disconnects on Type-C ports in host mode
+ private static final int HOST_STATE_UPDATE_DELAY = 1000;
// Timeout for entering USB request mode.
// Request is cancelled if host does not configure device within 10 seconds.
@@ -636,7 +640,9 @@
msg.arg1 = connected;
msg.arg2 = configured;
// debounce disconnects to avoid problems bringing up USB tethering
- sendMessageDelayed(msg, (connected == 0) ? UPDATE_DELAY : 0);
+ sendMessageDelayed(msg,
+ (connected == 0) ? (mScreenLocked ? DEVICE_STATE_UPDATE_DELAY
+ : DEVICE_STATE_UPDATE_DELAY_EXT) : 0);
}
public void updateHostState(UsbPort port, UsbPortStatus status) {
@@ -651,7 +657,7 @@
removeMessages(MSG_UPDATE_PORT_STATE);
Message msg = obtainMessage(MSG_UPDATE_PORT_STATE, args);
// debounce rapid transitions of connect/disconnect on type-c ports
- sendMessageDelayed(msg, UPDATE_DELAY);
+ sendMessageDelayed(msg, HOST_STATE_UPDATE_DELAY);
}
private void setAdbEnabled(boolean enable) {
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index e000265..b31b1f7 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -1257,7 +1257,7 @@
if (service != null) {
try {
return service.getPhoneAccountsSupportingScheme(uriScheme,
- mContext.getOpPackageName());
+ mContext.getOpPackageName()).getList();
} catch (RemoteException e) {
Log.e(TAG, "Error calling ITelecomService#getPhoneAccountsSupportingScheme", e);
}
@@ -1299,7 +1299,7 @@
if (service != null) {
try {
return service.getSelfManagedPhoneAccounts(mContext.getOpPackageName(),
- mContext.getAttributionTag());
+ mContext.getAttributionTag()).getList();
} catch (RemoteException e) {
Log.e(TAG, "Error calling ITelecomService#getSelfManagedPhoneAccounts()", e);
}
@@ -1325,7 +1325,7 @@
if (service != null) {
try {
return service.getCallCapablePhoneAccounts(includeDisabledAccounts,
- mContext.getOpPackageName(), mContext.getAttributionTag());
+ mContext.getOpPackageName(), mContext.getAttributionTag()).getList();
} catch (RemoteException e) {
Log.e(TAG, "Error calling ITelecomService#getCallCapablePhoneAccounts("
+ includeDisabledAccounts + ")", e);
@@ -1349,7 +1349,7 @@
ITelecomService service = getTelecomService();
if (service != null) {
try {
- return service.getPhoneAccountsForPackage(mContext.getPackageName());
+ return service.getPhoneAccountsForPackage(mContext.getPackageName()).getList();
} catch (RemoteException e) {
Log.e(TAG, "Error calling ITelecomService#getPhoneAccountsForPackage", e);
}
@@ -1409,7 +1409,7 @@
ITelecomService service = getTelecomService();
if (service != null) {
try {
- return service.getAllPhoneAccounts();
+ return service.getAllPhoneAccounts().getList();
} catch (RemoteException e) {
Log.e(TAG, "Error calling ITelecomService#getAllPhoneAccounts", e);
}
@@ -1428,7 +1428,7 @@
ITelecomService service = getTelecomService();
if (service != null) {
try {
- return service.getAllPhoneAccountHandles();
+ return service.getAllPhoneAccountHandles().getList();
} catch (RemoteException e) {
Log.e(TAG, "Error calling ITelecomService#getAllPhoneAccountHandles", e);
}
@@ -1444,9 +1444,14 @@
* when placing calls. The user may still need to enable the {@link PhoneAccount} within
* the phone app settings before the account is usable.
* <p>
+ * Note: Each package is limited to 10 {@link PhoneAccount} registrations.
+ * <p>
* A {@link SecurityException} will be thrown if an app tries to register a
* {@link PhoneAccountHandle} where the package name specified within
* {@link PhoneAccountHandle#getComponentName()} does not match the package name of the app.
+ * <p>
+ * A {@link IllegalArgumentException} will be thrown if an app tries to register a
+ * {@link PhoneAccount} when the upper bound limit, 10, has already been reached.
*
* @param account The complete {@link PhoneAccount}.
*/
diff --git a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
index 6f286d9..8f409c0 100644
--- a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
+++ b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
@@ -23,6 +23,7 @@
import android.net.Uri;
import android.os.Bundle;
import android.telecom.PhoneAccount;
+import android.content.pm.ParceledListSlice;
/**
* Interface used to interact with Telecom. Mostly this is used by TelephonyManager for passing
@@ -56,25 +57,25 @@
/**
* @see TelecomServiceImpl#getCallCapablePhoneAccounts
*/
- List<PhoneAccountHandle> getCallCapablePhoneAccounts(
+ ParceledListSlice<PhoneAccountHandle> getCallCapablePhoneAccounts(
boolean includeDisabledAccounts, String callingPackage, String callingFeatureId);
/**
* @see TelecomServiceImpl#getSelfManagedPhoneAccounts
*/
- List<PhoneAccountHandle> getSelfManagedPhoneAccounts(String callingPackage,
+ ParceledListSlice<PhoneAccountHandle> getSelfManagedPhoneAccounts(String callingPackage,
String callingFeatureId);
/**
* @see TelecomManager#getPhoneAccountsSupportingScheme
*/
- List<PhoneAccountHandle> getPhoneAccountsSupportingScheme(in String uriScheme,
+ ParceledListSlice<PhoneAccountHandle> getPhoneAccountsSupportingScheme(in String uriScheme,
String callingPackage);
/**
* @see TelecomManager#getPhoneAccountsForPackage
*/
- List<PhoneAccountHandle> getPhoneAccountsForPackage(in String packageName);
+ ParceledListSlice<PhoneAccountHandle> getPhoneAccountsForPackage(in String packageName);
/**
* @see TelecomManager#getPhoneAccount
@@ -89,12 +90,12 @@
/**
* @see TelecomManager#getAllPhoneAccounts
*/
- List<PhoneAccount> getAllPhoneAccounts();
+ ParceledListSlice<PhoneAccount> getAllPhoneAccounts();
/**
* @see TelecomManager#getAllPhoneAccountHandles
*/
- List<PhoneAccountHandle> getAllPhoneAccountHandles();
+ ParceledListSlice<PhoneAccountHandle> getAllPhoneAccountHandles();
/**
* @see TelecomServiceImpl#getSimCallManager
diff --git a/telephony/common/android/telephony/LocationAccessPolicy.java b/telephony/common/android/telephony/LocationAccessPolicy.java
index 85d59a2..9dfb0cc 100644
--- a/telephony/common/android/telephony/LocationAccessPolicy.java
+++ b/telephony/common/android/telephony/LocationAccessPolicy.java
@@ -361,7 +361,10 @@
return isCurrentProfile(context, uid) || checkInteractAcrossUsersFull(context, pid, uid);
}
- private static boolean isLocationModeEnabled(@NonNull Context context, @UserIdInt int userId) {
+ /**
+ * @return Whether location is enabled for the given user.
+ */
+ public static boolean isLocationModeEnabled(@NonNull Context context, @UserIdInt int userId) {
LocationManager locationManager = context.getSystemService(LocationManager.class);
if (locationManager == null) {
Log.w(TAG, "Couldn't get location manager, denying location access");
@@ -370,6 +373,14 @@
return locationManager.isLocationEnabledForUser(UserHandle.of(userId));
}
+ /**
+ * @return An array of packages that are always allowed to access location.
+ */
+ public static @NonNull String[] getLocationBypassPackages(@NonNull Context context) {
+ return context.getResources().getStringArray(
+ com.android.internal.R.array.config_serviceStateLocationAllowedPackages);
+ }
+
private static boolean checkInteractAcrossUsersFull(
@NonNull Context context, int pid, int uid) {
return checkManifestPermission(context, pid, uid,