Merge "Fixing wrong arguments used for permission check" into qt-dev
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
index ab174f4..f16fb1c 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
@@ -712,11 +712,25 @@
public boolean matches(WifiConfiguration config) {
if (config.isPasspoint()) {
return (isPasspoint() && config.FQDN.equals(mConfig.FQDN));
- } else {
- // Normal non-Passpoint network
- return ssid.equals(removeDoubleQuotes(config.SSID))
- && security == getSecurity(config)
- && (mConfig == null || mConfig.shared == config.shared);
+ }
+
+ if (!ssid.equals(removeDoubleQuotes(config.SSID))
+ || (mConfig != null && mConfig.shared != config.shared)) {
+ return false;
+ }
+
+ final int configSecurity = getSecurity(config);
+ final WifiManager wifiManager = getWifiManager();
+ switch (security) {
+ case SECURITY_PSK_SAE_TRANSITION:
+ return configSecurity == SECURITY_PSK
+ || (wifiManager.isWpa3SaeSupported() && configSecurity == SECURITY_SAE);
+ case SECURITY_OWE_TRANSITION:
+ return configSecurity == SECURITY_NONE
+ || (wifiManager.isEnhancedOpenSupported()
+ && configSecurity == SECURITY_OWE);
+ default:
+ return security == configSecurity;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistHandleReminderExpBehavior.java b/packages/SystemUI/src/com/android/systemui/assist/AssistHandleReminderExpBehavior.java
index 909b68b..0af333e 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistHandleReminderExpBehavior.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistHandleReminderExpBehavior.java
@@ -57,8 +57,8 @@
private static final String LEARNING_EVENT_COUNT_KEY = "reminder_exp_learning_event_count";
private static final String LEARNED_HINT_LAST_SHOWN_KEY =
"reminder_exp_learned_hint_last_shown";
- private static final long DEFAULT_LEARNING_TIME_MS = TimeUnit.DAYS.toMillis(200);
- private static final int DEFAULT_LEARNING_COUNT = 30000;
+ private static final long DEFAULT_LEARNING_TIME_MS = TimeUnit.DAYS.toMillis(10);
+ private static final int DEFAULT_LEARNING_COUNT = 10;
private static final long DEFAULT_SHOW_AND_GO_DELAYED_SHORT_DELAY_MS = 150;
private static final long DEFAULT_SHOW_AND_GO_DELAYED_LONG_DELAY_MS =
TimeUnit.SECONDS.toMillis(1);
@@ -66,7 +66,7 @@
TimeUnit.SECONDS.toMillis(3);
private static final boolean DEFAULT_SUPPRESS_ON_LOCKSCREEN = false;
private static final boolean DEFAULT_SUPPRESS_ON_LAUNCHER = false;
- private static final boolean DEFAULT_SUPPRESS_ON_APPS = false;
+ private static final boolean DEFAULT_SUPPRESS_ON_APPS = true;
private static final String[] DEFAULT_HOME_CHANGE_ACTIONS = new String[] {
PackageManagerWrapper.ACTION_PREFERRED_ACTIVITY_CHANGED,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/FloatingRotationButton.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/FloatingRotationButton.java
index 6bbeffa..deb314b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/FloatingRotationButton.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/FloatingRotationButton.java
@@ -115,7 +115,6 @@
return false;
}
mWindowManager.removeViewImmediate(mKeyButtonView);
- mRotationButtonController.cleanUp();
mIsShowing = false;
return true;
}
@@ -141,10 +140,7 @@
@Override
public void setOnClickListener(View.OnClickListener onClickListener) {
- mKeyButtonView.setOnClickListener(view -> {
- hide();
- onClickListener.onClick(view);
- });
+ mKeyButtonView.setOnClickListener(onClickListener);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
index 5708c1b..b56abcd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -871,9 +871,6 @@
boolean[] feedbackEnabled = new boolean[1];
int a11yFlags = getA11yButtonState(feedbackEnabled);
- mNavigationBarView.getRotationButtonController().setAccessibilityFeedbackEnabled(
- feedbackEnabled[0]);
-
boolean clickable = (a11yFlags & SYSUI_STATE_A11Y_BUTTON_CLICKABLE) != 0;
boolean longClickable = (a11yFlags & SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE) != 0;
mNavigationBarView.setAccessibilityButtonState(clickable, longClickable);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index ed486cd..9919abd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -1040,6 +1040,9 @@
reorient();
onNavigationModeChanged(mNavBarMode);
setUpSwipeUpOnboarding(isQuickStepSwipeUpEnabled());
+ if (mRotationButtonController != null) {
+ mRotationButtonController.registerListeners();
+ }
mEdgeBackGestureHandler.onNavBarAttached();
getViewTreeObserver().addOnComputeInternalInsetsListener(mOnComputeInternalInsetsListener);
@@ -1053,6 +1056,10 @@
for (int i = 0; i < mButtonDispatchers.size(); ++i) {
mButtonDispatchers.valueAt(i).onDestroy();
}
+ if (mRotationButtonController != null) {
+ mRotationButtonController.unregisterListeners();
+ }
+
mEdgeBackGestureHandler.onNavBarDetached();
getViewTreeObserver().removeOnComputeInternalInsetsListener(
mOnComputeInternalInsetsListener);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationButtonController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationButtonController.java
index 1e5406f..0147e7f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationButtonController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationButtonController.java
@@ -26,7 +26,7 @@
import android.content.ContentResolver;
import android.content.Context;
import android.os.Handler;
-import android.os.Message;
+import android.os.Looper;
import android.os.RemoteException;
import android.provider.Settings;
import android.view.IRotationWatcher.Stub;
@@ -34,6 +34,7 @@
import android.view.Surface;
import android.view.View;
import android.view.WindowManagerGlobal;
+import android.view.accessibility.AccessibilityManager;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
@@ -42,6 +43,7 @@
import com.android.systemui.R;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.TaskStackChangeListener;
+import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
import com.android.systemui.statusbar.policy.KeyButtonDrawable;
import com.android.systemui.statusbar.policy.RotationLockController;
@@ -64,8 +66,10 @@
private boolean mPendingRotationSuggestion;
private boolean mHoveringRotationSuggestion;
private RotationLockController mRotationLockController;
+ private AccessibilityManagerWrapper mAccessibilityManagerWrapper;
private TaskStackListenerImpl mTaskStackListener;
private Consumer<Integer> mRotWatcherListener;
+ private boolean mListenersRegistered = false;
private boolean mIsNavigationBarShowing;
private final Runnable mRemoveRotationProposal =
@@ -73,22 +77,17 @@
private final Runnable mCancelPendingRotationProposal =
() -> mPendingRotationSuggestion = false;
private Animator mRotateHideAnimator;
- private boolean mAccessibilityFeedbackEnabled;
private final Context mContext;
private final RotationButton mRotationButton;
+ private final Handler mMainThreadHandler = new Handler(Looper.getMainLooper());
private final Stub mRotationWatcher = new Stub() {
@Override
public void onRotationChanged(final int rotation) throws RemoteException {
- if (mRotationButton.getCurrentView() == null) {
- return;
- }
-
// We need this to be scheduled as early as possible to beat the redrawing of
// window in response to the orientation change.
- Handler h = mRotationButton.getCurrentView().getHandler();
- Message msg = Message.obtain(h, () -> {
+ mMainThreadHandler.postAtFrontOfQueue(() -> {
// If the screen rotation changes while locked, potentially update lock to flow with
// new screen rotation and hide any showing suggestions.
if (mRotationLockController.isRotationLocked()) {
@@ -102,8 +101,6 @@
mRotWatcherListener.accept(rotation);
}
});
- msg.setAsynchronous(true);
- h.sendMessageAtFrontOfQueue(msg);
}
};
@@ -124,40 +121,49 @@
mStyleRes = style;
mIsNavigationBarShowing = true;
mRotationLockController = Dependency.get(RotationLockController.class);
+ mAccessibilityManagerWrapper = Dependency.get(AccessibilityManagerWrapper.class);
// Register the task stack listener
mTaskStackListener = new TaskStackListenerImpl();
- ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener);
mRotationButton.setOnClickListener(this::onRotateSuggestionClick);
mRotationButton.setOnHoverListener(this::onRotateSuggestionHover);
+ }
+ void registerListeners() {
+ if (mListenersRegistered) {
+ return;
+ }
+
+ mListenersRegistered = true;
try {
WindowManagerGlobal.getWindowManagerService()
.watchRotation(mRotationWatcher, mContext.getDisplay().getDisplayId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
+
+ ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener);
}
- void cleanUp() {
- // Unregister the task stack listener
- ActivityManagerWrapper.getInstance().unregisterTaskStackListener(mTaskStackListener);
+ void unregisterListeners() {
+ if (!mListenersRegistered) {
+ return;
+ }
+ mListenersRegistered = false;
try {
WindowManagerGlobal.getWindowManagerService().removeRotationWatcher(mRotationWatcher);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
+
+ ActivityManagerWrapper.getInstance().unregisterTaskStackListener(mTaskStackListener);
}
void addRotationCallback(Consumer<Integer> watcher) {
mRotWatcherListener = watcher;
}
- void setAccessibilityFeedbackEnabled(boolean flag) {
- mAccessibilityFeedbackEnabled = flag;
- }
-
void setRotationLockedAtAngle(int rotationSuggestion) {
mRotationLockController.setRotationLockedAtAngle(true /* locked */, rotationSuggestion);
}
@@ -185,7 +191,7 @@
// Clear any pending suggestion flag as it has either been nullified or is being shown
mPendingRotationSuggestion = false;
- view.removeCallbacks(mCancelPendingRotationProposal);
+ mMainThreadHandler.removeCallbacks(mCancelPendingRotationProposal);
// Handle the visibility change and animation
if (visible) { // Appear and change (cannot force)
@@ -255,13 +261,9 @@
return;
}
- final View currentView = mRotationButton.getCurrentView();
-
// If window rotation matches suggested rotation, remove any current suggestions
if (rotation == windowRotation) {
- if (currentView != null) {
- currentView.removeCallbacks(mRemoveRotationProposal);
- }
+ mMainThreadHandler.removeCallbacks(mRemoveRotationProposal);
setRotateSuggestionButtonState(false /* visible */);
return;
}
@@ -285,11 +287,9 @@
// If the navbar isn't shown, flag the rotate icon to be shown should the navbar become
// visible given some time limit.
mPendingRotationSuggestion = true;
- if (currentView != null) {
- currentView.removeCallbacks(mCancelPendingRotationProposal);
- currentView.postDelayed(mCancelPendingRotationProposal,
- NAVBAR_HIDDEN_PENDING_ICON_TIMEOUT_MS);
- }
+ mMainThreadHandler.removeCallbacks(mCancelPendingRotationProposal);
+ mMainThreadHandler.postDelayed(mCancelPendingRotationProposal,
+ NAVBAR_HIDDEN_PENDING_ICON_TIMEOUT_MS);
}
}
@@ -334,9 +334,7 @@
private void onRotationSuggestionsDisabled() {
// Immediately hide the rotate button and clear any planned removal
setRotateSuggestionButtonState(false /* visible */, true /* force */);
- if (mRotationButton.getCurrentView() != null) {
- mRotationButton.getCurrentView().removeCallbacks(mRemoveRotationProposal);
- }
+ mMainThreadHandler.removeCallbacks(mRemoveRotationProposal);
}
private void showAndLogRotationSuggestion() {
@@ -369,10 +367,6 @@
}
private void rescheduleRotationTimeout(final boolean reasonHover) {
- if (mRotationButton.getCurrentView() == null) {
- return;
- }
-
// May be called due to a new rotation proposal or a change in hover state
if (reasonHover) {
// Don't reschedule if a hide animator is running
@@ -382,16 +376,16 @@
}
// Stop any pending removal
- mRotationButton.getCurrentView().removeCallbacks(mRemoveRotationProposal);
+ mMainThreadHandler.removeCallbacks(mRemoveRotationProposal);
// Schedule timeout
- mRotationButton.getCurrentView().postDelayed(mRemoveRotationProposal,
+ mMainThreadHandler.postDelayed(mRemoveRotationProposal,
computeRotationProposalTimeout());
}
private int computeRotationProposalTimeout() {
- if (mAccessibilityFeedbackEnabled) return 10000;
- if (mHoveringRotationSuggestion) return 8000;
- return 5000;
+ return mAccessibilityManagerWrapper.getRecommendedTimeoutMillis(
+ mHoveringRotationSuggestion ? 16000 : 5000,
+ AccessibilityManager.FLAG_CONTENT_CONTROLS);
}
private boolean isRotateSuggestionIntroduced() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationContextButton.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationContextButton.java
index 24e7336..bd96752 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationContextButton.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationContextButton.java
@@ -64,13 +64,6 @@
}
@Override
- public void onDestroy() {
- if (mRotationButtonController != null) {
- mRotationButtonController.cleanUp();
- }
- }
-
- @Override
public void onNavigationModeChanged(int mode) {
mNavBarMode = mode;
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 5f4d113..d2031b6 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -111,9 +111,6 @@
import static com.android.server.pm.PackageManagerServiceUtils.getLastModifiedTime;
import static com.android.server.pm.PackageManagerServiceUtils.logCriticalInfo;
import static com.android.server.pm.PackageManagerServiceUtils.verifySignatures;
-import static com.android.server.pm.permission.PermissionsState.PERMISSION_OPERATION_FAILURE;
-import static com.android.server.pm.permission.PermissionsState.PERMISSION_OPERATION_SUCCESS;
-import static com.android.server.pm.permission.PermissionsState.PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED;
import android.Manifest;
import android.annotation.IntDef;
@@ -294,6 +291,7 @@
import com.android.internal.util.DumpUtils;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.IndentingPrintWriter;
+import com.android.internal.util.IntPair;
import com.android.internal.util.Preconditions;
import com.android.server.AttributeCache;
import com.android.server.DeviceIdleController;
@@ -19801,6 +19799,8 @@
return;
}
+ final String packageName = ps.pkg.packageName;
+
// These are flags that can change base on user actions.
final int userSettableMask = FLAG_PERMISSION_USER_SET
| FLAG_PERMISSION_USER_FIXED
@@ -19810,8 +19810,59 @@
final int policyOrSystemFlags = FLAG_PERMISSION_SYSTEM_FIXED
| FLAG_PERMISSION_POLICY_FIXED;
- boolean writeInstallPermissions = false;
- boolean writeRuntimePermissions = false;
+ // Delay and combine non-async permission callbacks
+ final boolean[] permissionRemoved = new boolean[1];
+ final ArraySet<Long> revokedPermissions = new ArraySet<>();
+ final SparseBooleanArray updatedUsers = new SparseBooleanArray();
+
+ PermissionCallback delayingPermCallback = new PermissionCallback() {
+ public void onGidsChanged(int appId, int userId) {
+ mPermissionCallback.onGidsChanged(appId, userId);
+ }
+
+ public void onPermissionChanged() {
+ mPermissionCallback.onPermissionChanged();
+ }
+
+ public void onPermissionGranted(int uid, int userId) {
+ mPermissionCallback.onPermissionGranted(uid, userId);
+ }
+
+ public void onInstallPermissionGranted() {
+ mPermissionCallback.onInstallPermissionGranted();
+ }
+
+ public void onPermissionRevoked(int uid, int userId) {
+ revokedPermissions.add(IntPair.of(uid, userId));
+
+ updatedUsers.put(userId, true);
+ }
+
+ public void onInstallPermissionRevoked() {
+ mPermissionCallback.onInstallPermissionRevoked();
+ }
+
+ public void onPermissionUpdated(int[] updatedUserIds, boolean sync) {
+ for (int userId : updatedUserIds) {
+ if (sync) {
+ updatedUsers.put(userId, true);
+ } else {
+ // Don't override sync=true by sync=false
+ if (!updatedUsers.get(userId)) {
+ updatedUsers.put(userId, false);
+ }
+ }
+ }
+ }
+
+ public void onPermissionRemoved() {
+ permissionRemoved[0] = true;
+ }
+
+ public void onInstallPermissionUpdated() {
+ mPermissionCallback.onInstallPermissionUpdated();
+ }
+ };
final int permissionCount = ps.pkg.requestedPermissions.size();
for (int i = 0; i < permissionCount; i++) {
@@ -19843,26 +19894,20 @@
}
}
- final PermissionsState permissionsState = ps.getPermissionsState();
-
- final int oldFlags = permissionsState.getPermissionFlags(permName, userId);
+ final int oldFlags = mPermissionManager.getPermissionFlags(permName, packageName,
+ Process.SYSTEM_UID, userId);
// Always clear the user settable flags.
- final boolean hasInstallState =
- permissionsState.getInstallPermissionState(permName) != null;
// If permission review is enabled and this is a legacy app, mark the
// permission as requiring a review as this is the initial state.
int flags = 0;
if (ps.pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M && bp.isRuntime()) {
flags |= FLAG_PERMISSION_REVIEW_REQUIRED | FLAG_PERMISSION_REVOKE_ON_UPGRADE;
}
- if (permissionsState.updatePermissionFlags(bp, userId, userSettableMask, flags)) {
- if (hasInstallState) {
- writeInstallPermissions = true;
- } else {
- writeRuntimePermissions = true;
- }
- }
+
+ mPermissionManager.updatePermissionFlags(permName, packageName,
+ userSettableMask, flags, Process.SYSTEM_UID, userId, false,
+ delayingPermCallback);
// Below is only runtime permission handling.
if (!bp.isRuntime()) {
@@ -19876,35 +19921,42 @@
// If this permission was granted by default, make sure it is.
if ((oldFlags & FLAG_PERMISSION_GRANTED_BY_DEFAULT) != 0) {
- if (permissionsState.grantRuntimePermission(bp, userId)
- != PERMISSION_OPERATION_FAILURE) {
- writeRuntimePermissions = true;
- }
+ mPermissionManager.grantRuntimePermission(permName, packageName, false,
+ Process.SYSTEM_UID, userId, delayingPermCallback);
// If permission review is enabled the permissions for a legacy apps
// are represented as constantly granted runtime ones, so don't revoke.
} else if ((flags & FLAG_PERMISSION_REVIEW_REQUIRED) == 0) {
// Otherwise, reset the permission.
- final int revokeResult = permissionsState.revokeRuntimePermission(bp, userId);
- switch (revokeResult) {
- case PERMISSION_OPERATION_SUCCESS:
- case PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED: {
- writeRuntimePermissions = true;
- final int appId = ps.appId;
- mHandler.post(
- () -> killUid(appId, userId, KILL_APP_REASON_PERMISSIONS_REVOKED));
- } break;
- }
+ mPermissionManager.revokeRuntimePermission(permName, packageName, false, userId,
+ delayingPermCallback);
}
}
- // Synchronously write as we are taking permissions away.
- if (writeRuntimePermissions) {
- mSettings.writeRuntimePermissionsForUserLPr(userId, true);
+ // Execute delayed callbacks
+ if (permissionRemoved[0]) {
+ mPermissionCallback.onPermissionRemoved();
}
- // Synchronously write as we are taking permissions away.
- if (writeInstallPermissions) {
- mSettings.writeLPr();
+ // Slight variation on the code in mPermissionCallback.onPermissionRevoked() as we cannot
+ // kill uid while holding mPackages-lock
+ if (!revokedPermissions.isEmpty()) {
+ int numRevokedPermissions = revokedPermissions.size();
+ for (int i = 0; i < numRevokedPermissions; i++) {
+ int revocationUID = IntPair.first(revokedPermissions.valueAt(i));
+ int revocationUserId = IntPair.second(revokedPermissions.valueAt(i));
+
+ mOnPermissionChangeListeners.onPermissionsChanged(revocationUID);
+
+ // Kill app later as we are holding mPackages
+ mHandler.post(() -> killUid(UserHandle.getAppId(revocationUID), revocationUserId,
+ KILL_APP_REASON_PERMISSIONS_REVOKED));
+ }
+ }
+
+ int numUpdatedUsers = updatedUsers.size();
+ for (int i = 0; i < numUpdatedUsers; i++) {
+ mSettings.writeRuntimePermissionsForUserLPr(updatedUsers.keyAt(i),
+ updatedUsers.valueAt(i));
}
}
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index e5f914d..a7da3ec 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -3127,6 +3127,27 @@
}
@Override
+ public @NonNull ArrayList<PermissionInfo> getAllPermissionWithProtectionLevel(
+ @PermissionInfo.Protection int protectionLevel) {
+ ArrayList<PermissionInfo> matchingPermissions = new ArrayList<>();
+
+ synchronized (PermissionManagerService.this.mLock) {
+ int numTotalPermissions = mSettings.mPermissions.size();
+
+ for (int i = 0; i < numTotalPermissions; i++) {
+ BasePermission bp = mSettings.mPermissions.valueAt(i);
+
+ if (bp.perm != null && bp.perm.info != null
+ && bp.protectionLevel == protectionLevel) {
+ matchingPermissions.add(bp.perm.info);
+ }
+ }
+ }
+
+ return matchingPermissions;
+ }
+
+ @Override
public @Nullable byte[] backupRuntimePermissions(@NonNull UserHandle user) {
return PermissionManagerService.this.backupRuntimePermissions(user);
}
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
index 313de3d..e5e9598 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
@@ -195,4 +195,8 @@
/** HACK HACK methods to allow for partial migration of data to the PermissionManager class */
public abstract @Nullable BasePermission getPermissionTEMP(@NonNull String permName);
+
+ /** Get all permission that have a certain protection level */
+ public abstract @NonNull ArrayList<PermissionInfo> getAllPermissionWithProtectionLevel(
+ @PermissionInfo.Protection int protectionLevel);
}
diff --git a/services/core/java/com/android/server/policy/PermissionPolicyService.java b/services/core/java/com/android/server/policy/PermissionPolicyService.java
index 93b11bef..68feb4a 100644
--- a/services/core/java/com/android/server/policy/PermissionPolicyService.java
+++ b/services/core/java/com/android/server/policy/PermissionPolicyService.java
@@ -23,6 +23,7 @@
import static android.app.AppOpsManager.MODE_IGNORED;
import static android.app.AppOpsManager.OP_NONE;
import static android.content.pm.PackageManager.FLAG_PERMISSION_APPLY_RESTRICTION;
+import static android.content.pm.PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED;
import static android.content.pm.PackageManager.GET_PERMISSIONS;
import android.annotation.NonNull;
@@ -41,20 +42,27 @@
import android.content.pm.PermissionInfo;
import android.os.Build;
import android.os.Process;
+import android.os.RemoteException;
+import android.os.ServiceManager;
import android.os.UserHandle;
import android.os.UserManagerInternal;
import android.permission.PermissionControllerManager;
-import android.permission.PermissionManagerInternal;
import android.provider.Telephony;
import android.telecom.TelecomManager;
+import android.util.ArraySet;
+import android.util.Pair;
import android.util.Slog;
import android.util.SparseBooleanArray;
import android.util.SparseIntArray;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.app.IAppOpsCallback;
+import com.android.internal.app.IAppOpsService;
+import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.FgThread;
import com.android.server.LocalServices;
import com.android.server.SystemService;
+import com.android.server.pm.permission.PermissionManagerServiceInternal;
import java.util.ArrayList;
import java.util.concurrent.CountDownLatch;
@@ -76,6 +84,13 @@
@GuardedBy("mLock")
private final SparseBooleanArray mIsStarted = new SparseBooleanArray();
+ /**
+ * Whether an async {@link #synchronizePackagePermissionsAndAppOpsForUser} is currently
+ * scheduled for a package/user.
+ */
+ @GuardedBy("mLock")
+ private final ArraySet<Pair<String, Integer>> mIsPackageSyncsScheduled = new ArraySet<>();
+
public PermissionPolicyService(@NonNull Context context) {
super(context);
@@ -86,8 +101,10 @@
public void onStart() {
final PackageManagerInternal packageManagerInternal = LocalServices.getService(
PackageManagerInternal.class);
- final PermissionManagerInternal permManagerInternal = LocalServices.getService(
- PermissionManagerInternal.class);
+ final PermissionManagerServiceInternal permManagerInternal = LocalServices.getService(
+ PermissionManagerServiceInternal.class);
+ final IAppOpsService appOpsService = IAppOpsService.Stub.asInterface(
+ ServiceManager.getService(Context.APP_OPS_SERVICE));
packageManagerInternal.getPackageList(new PackageListObserver() {
@Override
@@ -111,11 +128,62 @@
});
permManagerInternal.addOnRuntimePermissionStateChangedListener(
- (packageName, changedUserId) -> {
- if (isStarted(changedUserId)) {
- synchronizePackagePermissionsAndAppOpsForUser(packageName, changedUserId);
+ this::synchronizePackagePermissionsAndAppOpsAsyncForUser);
+
+ IAppOpsCallback appOpsListener = new IAppOpsCallback.Stub() {
+ public void opChanged(int op, int uid, String packageName) {
+ synchronizePackagePermissionsAndAppOpsAsyncForUser(packageName,
+ UserHandle.getUserId(uid));
+ }
+ };
+
+ final ArrayList<PermissionInfo> dangerousPerms =
+ permManagerInternal.getAllPermissionWithProtectionLevel(
+ PermissionInfo.PROTECTION_DANGEROUS);
+
+ try {
+ int numDangerousPerms = dangerousPerms.size();
+ for (int i = 0; i < numDangerousPerms; i++) {
+ PermissionInfo perm = dangerousPerms.get(i);
+
+ if (perm.isHardRestricted() || perm.backgroundPermission != null) {
+ appOpsService.startWatchingMode(AppOpsManager.permissionToOpCode(perm.name),
+ null, appOpsListener);
+ } else if (perm.isSoftRestricted()) {
+ appOpsService.startWatchingMode(AppOpsManager.permissionToOpCode(perm.name),
+ null, appOpsListener);
+
+ SoftRestrictedPermissionPolicy policy =
+ SoftRestrictedPermissionPolicy.forPermission(null, null, null,
+ perm.name);
+ if (policy.resolveAppOp() != OP_NONE) {
+ appOpsService.startWatchingMode(policy.resolveAppOp(), null,
+ appOpsListener);
}
- });
+ }
+ }
+ } catch (RemoteException doesNotHappen) {
+ Slog.wtf(LOG_TAG, "Cannot set up app-ops listener");
+ }
+ }
+
+ private void synchronizePackagePermissionsAndAppOpsAsyncForUser(@NonNull String packageName,
+ @UserIdInt int changedUserId) {
+ if (isStarted(changedUserId)) {
+ synchronized (mLock) {
+ if (mIsPackageSyncsScheduled.add(new Pair<>(packageName, changedUserId))) {
+ FgThread.getHandler().sendMessage(PooledLambda.obtainMessage(
+ PermissionPolicyService
+ ::synchronizePackagePermissionsAndAppOpsForUser,
+ this, packageName, changedUserId));
+ } else {
+ if (DEBUG) {
+ Slog.v(LOG_TAG, "sync for " + packageName + "/" + changedUserId
+ + " already scheduled");
+ }
+ }
+ }
+ }
}
@Override
@@ -230,10 +298,14 @@
*/
private void synchronizePackagePermissionsAndAppOpsForUser(@NonNull String packageName,
@UserIdInt int userId) {
+ synchronized (mLock) {
+ mIsPackageSyncsScheduled.remove(new Pair<>(packageName, userId));
+ }
+
if (DEBUG) {
Slog.v(LOG_TAG,
- "synchronizePackagePermissionsAndAppOpsForUser(" + packageName + ", " + userId
- + ")");
+ "synchronizePackagePermissionsAndAppOpsForUser(" + packageName + ", "
+ + userId + ")");
}
final PackageManagerInternal packageManagerInternal = LocalServices.getService(
@@ -336,6 +408,16 @@
*/
private final @NonNull ArrayList<OpToUnrestrict> mOpsToForeground = new ArrayList<>();
+ /**
+ * All ops that need to be flipped to foreground if allow.
+ *
+ * Currently, only used by the foreground/background permissions logic.
+ *
+ * @see #syncPackages
+ */
+ private final @NonNull ArrayList<OpToUnrestrict> mOpsToForegroundIfAllow =
+ new ArrayList<>();
+
PermissionToOpSynchroniser(@NonNull Context context) {
mContext = context;
mPackageManager = context.getPackageManager();
@@ -351,22 +433,27 @@
final int allowCount = mOpsToAllow.size();
for (int i = 0; i < allowCount; i++) {
final OpToUnrestrict op = mOpsToAllow.get(i);
- setUidModeAllowed(op.code, op.uid);
+ setUidModeAllowed(op.code, op.uid, op.packageName);
}
final int allowIfDefaultCount = mOpsToAllowIfDefault.size();
for (int i = 0; i < allowIfDefaultCount; i++) {
final OpToUnrestrict op = mOpsToAllowIfDefault.get(i);
setUidModeAllowedIfDefault(op.code, op.uid, op.packageName);
}
- final int foregroundCount = mOpsToForeground.size();
+ final int foregroundCount = mOpsToForegroundIfAllow.size();
for (int i = 0; i < foregroundCount; i++) {
+ final OpToUnrestrict op = mOpsToForegroundIfAllow.get(i);
+ setUidModeForegroundIfAllow(op.code, op.uid, op.packageName);
+ }
+ final int foregroundIfAllowCount = mOpsToForeground.size();
+ for (int i = 0; i < foregroundIfAllowCount; i++) {
final OpToUnrestrict op = mOpsToForeground.get(i);
- setUidModeForeground(op.code, op.uid);
+ setUidModeForeground(op.code, op.uid, op.packageName);
}
final int ignoreCount = mOpsToIgnore.size();
for (int i = 0; i < ignoreCount; i++) {
final OpToUnrestrict op = mOpsToIgnore.get(i);
- setUidModeIgnored(op.code, op.uid);
+ setUidModeIgnored(op.code, op.uid, op.packageName);
}
final int ignoreIfDefaultCount = mOpsToIgnoreIfDefault.size();
for (int i = 0; i < ignoreIfDefaultCount; i++) {
@@ -459,6 +546,24 @@
}
}
+ private boolean isBgPermRestricted(@NonNull String pkg, @NonNull String perm, int uid) {
+ try {
+ final PermissionInfo bgPermInfo = mPackageManager.getPermissionInfo(perm, 0);
+
+ if (bgPermInfo.isSoftRestricted()) {
+ Slog.wtf(LOG_TAG, "Support for soft restricted background permissions not "
+ + "implemented");
+ }
+
+ return bgPermInfo.isHardRestricted() && (mPackageManager.getPermissionFlags(
+ perm, pkg, UserHandle.getUserHandleForUid(uid))
+ & FLAG_PERMISSION_APPLY_RESTRICTION) != 0;
+ } catch (NameNotFoundException e) {
+ Slog.w(LOG_TAG, "Cannot read permission state of " + perm, e);
+ return false;
+ }
+ }
+
/**
* Add op that belong to a foreground permission for later processing in
* {@link #syncPackages()}.
@@ -481,26 +586,27 @@
final String pkgName = pkg.packageName;
final int uid = pkg.applicationInfo.uid;
- if (mPackageManager.checkPermission(permission, pkgName)
- == PackageManager.PERMISSION_GRANTED) {
- boolean isBgHardRestricted = false;
- try {
- final PermissionInfo bgPermInfo = mPackageManager.getPermissionInfo(
- bgPermissionName, 0);
+ // App does not support runtime permissions. Hence the state is encoded in the app-op.
+ // To not override unrecoverable state don't change app-op unless bg perm is reviewed.
+ if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M) {
+ // If the review is required for this permission, the grant state does not
+ // really matter. To have a stable state, don't change the app-op if review is still
+ // pending.
+ int flags = mPackageManager.getPermissionFlags(bgPermissionName,
+ pkg.packageName, UserHandle.getUserHandleForUid(uid));
- if (bgPermInfo.isSoftRestricted()) {
- Slog.wtf(LOG_TAG, "Support for soft restricted background permissions not "
- + "implemented");
- }
-
- isBgHardRestricted =
- bgPermInfo.isHardRestricted() && (mPackageManager.getPermissionFlags(
- bgPermissionName, pkgName, UserHandle.getUserHandleForUid(uid))
- & FLAG_PERMISSION_APPLY_RESTRICTION) != 0;
- } catch (NameNotFoundException e) {
- Slog.w(LOG_TAG, "Cannot read permission state of " + bgPermissionName, e);
+ if ((flags & FLAG_PERMISSION_REVIEW_REQUIRED) == 0
+ && isBgPermRestricted(pkgName, bgPermissionName, uid)) {
+ mOpsToForegroundIfAllow.add(new OpToUnrestrict(uid, pkgName, opCode));
}
+ return;
+ }
+
+ if (mPackageManager.checkPermission(permission, pkgName)
+ == PackageManager.PERMISSION_GRANTED) {
+ final boolean isBgHardRestricted = isBgPermRestricted(pkgName, bgPermissionName,
+ uid);
final boolean isBgPermGranted = mPackageManager.checkPermission(bgPermissionName,
pkgName) == PackageManager.PERMISSION_GRANTED;
@@ -554,45 +660,49 @@
}
private void setUidModeAllowedIfDefault(int opCode, int uid, @NonNull String packageName) {
- setUidModeIfDefault(opCode, uid, AppOpsManager.MODE_ALLOWED, packageName);
+ setUidModeIfMode(opCode, uid, MODE_DEFAULT, MODE_ALLOWED, packageName);
}
- private void setUidModeAllowed(int opCode, int uid) {
- mAppOpsManager.setUidMode(opCode, uid, AppOpsManager.MODE_ALLOWED);
+ private void setUidModeAllowed(int opCode, int uid, @NonNull String packageName) {
+ setUidMode(opCode, uid, MODE_ALLOWED, packageName);
}
- private void setUidModeForeground(int opCode, int uid) {
- mAppOpsManager.setUidMode(opCode, uid, AppOpsManager.MODE_FOREGROUND);
+ private void setUidModeForegroundIfAllow(int opCode, int uid, @NonNull String packageName) {
+ setUidModeIfMode(opCode, uid, MODE_ALLOWED, MODE_FOREGROUND, packageName);
+ }
+
+ private void setUidModeForeground(int opCode, int uid, @NonNull String packageName) {
+ setUidMode(opCode, uid, MODE_FOREGROUND, packageName);
}
private void setUidModeIgnoredIfDefault(int opCode, int uid, @NonNull String packageName) {
- setUidModeIfDefault(opCode, uid, AppOpsManager.MODE_IGNORED, packageName);
+ setUidModeIfMode(opCode, uid, MODE_DEFAULT, MODE_IGNORED, packageName);
}
- private void setUidModeIgnored(int opCode, int uid) {
- mAppOpsManager.setUidMode(opCode, uid, MODE_IGNORED);
+ private void setUidModeIgnored(int opCode, int uid, @NonNull String packageName) {
+ setUidMode(opCode, uid, MODE_IGNORED, packageName);
}
- private void setUidModeIfDefault(int opCode, int uid, int mode,
+ private void setUidMode(int opCode, int uid, int mode,
@NonNull String packageName) {
- final int currentMode;
- try {
- currentMode = mAppOpsManager.unsafeCheckOpRaw(AppOpsManager
- .opToPublicName(opCode), uid, packageName);
- } catch (SecurityException e) {
- // This might happen if the app was uninstalled in between the add and sync step.
- // In this case the package name cannot be resolved inside appops service and hence
- // the uid does not match.
- Slog.w(LOG_TAG, "Cannot set mode of uid=" + uid + " op=" + opCode + " to " + mode,
- e);
- return;
- }
+ final int currentMode = mAppOpsManager.unsafeCheckOpRaw(AppOpsManager
+ .opToPublicName(opCode), uid, packageName);
- if (currentMode == MODE_DEFAULT) {
+ if (currentMode != mode) {
mAppOpsManager.setUidMode(opCode, uid, mode);
}
}
+ private void setUidModeIfMode(int opCode, int uid, int requiredModeBefore, int newMode,
+ @NonNull String packageName) {
+ final int currentMode = mAppOpsManager.unsafeCheckOpRaw(AppOpsManager
+ .opToPublicName(opCode), uid, packageName);
+
+ if (currentMode == requiredModeBefore) {
+ mAppOpsManager.setUidMode(opCode, uid, newMode);
+ }
+ }
+
private void setUidModeDefault(int opCode, int uid) {
mAppOpsManager.setUidMode(opCode, uid, MODE_DEFAULT);
}
diff --git a/services/core/java/com/android/server/policy/SoftRestrictedPermissionPolicy.java b/services/core/java/com/android/server/policy/SoftRestrictedPermissionPolicy.java
index 90e0dc4..1658833 100644
--- a/services/core/java/com/android/server/policy/SoftRestrictedPermissionPolicy.java
+++ b/services/core/java/com/android/server/policy/SoftRestrictedPermissionPolicy.java
@@ -29,6 +29,7 @@
import static android.content.pm.PackageManager.FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.AppOpsManager;
import android.content.Context;
import android.content.pm.ApplicationInfo;
@@ -75,14 +76,16 @@
* Get the policy for a soft restricted permission.
*
* @param context A context to use
- * @param appInfo The application the permission belongs to
- * @param user The user the app belongs to
+ * @param appInfo The application the permission belongs to. Can be {@code null}, but then
+ * only {@link #resolveAppOp} will work.
+ * @param user The user the app belongs to. Can be {@code null}, but then only
+ * {@link #resolveAppOp} will work.
* @param permission The name of the permission
*
* @return The policy for this permission
*/
public static @NonNull SoftRestrictedPermissionPolicy forPermission(@NonNull Context context,
- @NonNull ApplicationInfo appInfo, @NonNull UserHandle user,
+ @Nullable ApplicationInfo appInfo, @Nullable UserHandle user,
@NonNull String permission) {
switch (permission) {
// Storage uses a special app op to decide the mount state and supports soft restriction
@@ -90,13 +93,26 @@
// collections.
case READ_EXTERNAL_STORAGE:
case WRITE_EXTERNAL_STORAGE: {
- int flags = context.getPackageManager().getPermissionFlags(
- permission, appInfo.packageName, user);
- boolean applyRestriction = (flags & FLAG_PERMISSION_APPLY_RESTRICTION) != 0;
- boolean isWhiteListed = (flags & FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT) != 0;
- boolean hasRequestedLegacyExternalStorage =
- appInfo.hasRequestedLegacyExternalStorage();
- int targetSDK = appInfo.targetSdkVersion;
+ final int flags;
+ final boolean applyRestriction;
+ final boolean isWhiteListed;
+ final boolean hasRequestedLegacyExternalStorage;
+ final int targetSDK;
+
+ if (appInfo != null) {
+ flags = context.getPackageManager().getPermissionFlags(permission,
+ appInfo.packageName, user);
+ applyRestriction = (flags & FLAG_PERMISSION_APPLY_RESTRICTION) != 0;
+ isWhiteListed = (flags & FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT) != 0;
+ hasRequestedLegacyExternalStorage = appInfo.hasRequestedLegacyExternalStorage();
+ targetSDK = appInfo.targetSdkVersion;
+ } else {
+ flags = 0;
+ applyRestriction = false;
+ isWhiteListed = false;
+ hasRequestedLegacyExternalStorage = false;
+ targetSDK = 0;
+ }
return new SoftRestrictedPermissionPolicy() {
@Override
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 9189279..be3b924 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -79,6 +79,7 @@
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_PLACE_SURFACES;
import static com.android.server.wm.WindowManagerService.logWithStack;
import static com.android.server.wm.WindowState.LEGACY_POLICY_VISIBILITY;
+import static com.android.server.wm.WindowStateAnimator.HAS_DRAWN;
import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_AFTER_ANIM;
import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_BEFORE_ANIM;
@@ -540,6 +541,14 @@
// If the app was already visible, don't reset the waitingToShow state.
if (isHidden()) {
waitingToShow = true;
+
+ // Let's reset the draw state in order to prevent the starting window to be
+ // immediately dismissed when the app still has the surface.
+ forAllWindows(w -> {
+ if (w.mWinAnimator.mDrawState == HAS_DRAWN) {
+ w.mWinAnimator.resetDrawState();
+ }
+ }, true /* traverseTopToBottom */);
}
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index ce8720a..57fa2ed 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -7626,22 +7626,30 @@
@Override
public boolean injectInputAfterTransactionsApplied(InputEvent ev, int mode) {
- boolean shouldWaitForAnimToComplete = false;
+ boolean isDown;
+ boolean isUp;
+
if (ev instanceof KeyEvent) {
KeyEvent keyEvent = (KeyEvent) ev;
- shouldWaitForAnimToComplete = keyEvent.getSource() == InputDevice.SOURCE_MOUSE
- || keyEvent.getAction() == KeyEvent.ACTION_DOWN;
- } else if (ev instanceof MotionEvent) {
+ isDown = keyEvent.getAction() == KeyEvent.ACTION_DOWN;
+ isUp = keyEvent.getAction() == KeyEvent.ACTION_UP;
+ } else {
MotionEvent motionEvent = (MotionEvent) ev;
- shouldWaitForAnimToComplete = motionEvent.getSource() == InputDevice.SOURCE_MOUSE
- || motionEvent.getAction() == MotionEvent.ACTION_DOWN;
+ isDown = motionEvent.getAction() == MotionEvent.ACTION_DOWN;
+ isUp = motionEvent.getAction() == MotionEvent.ACTION_UP;
}
- if (shouldWaitForAnimToComplete) {
+ // For ACTION_DOWN, syncInputTransactions before injecting input.
+ // For ACTION_UP, sync after injecting.
+ if (isDown) {
syncInputTransactions();
}
-
- return LocalServices.getService(InputManagerInternal.class).injectInputEvent(ev, mode);
+ final boolean result =
+ LocalServices.getService(InputManagerInternal.class).injectInputEvent(ev, mode);
+ if (isUp) {
+ syncInputTransactions();
+ }
+ return result;
}
@Override
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index ba59cdb..8b61208 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -6443,7 +6443,7 @@
.setAdmin(admin)
.setStrings(vpnPackage)
.setBoolean(lockdown)
- .setInt(/* number of vpn packages */ 0)
+ .setInt(lockdownWhitelist != null ? lockdownWhitelist.size() : 0)
.write();
} finally {
mInjector.binderRestoreCallingIdentity(token);
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 1ac81db..a10454e 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -791,6 +791,14 @@
public static final int PROFILE_CLASS_DEFAULT = PROFILE_CLASS_UNSET;
/**
+ * IMSI (International Mobile Subscriber Identity).
+ * <P>Type: TEXT </P>
+ * @hide
+ */
+ //TODO: add @SystemApi
+ public static final String IMSI = "imsi";
+
+ /**
* Broadcast Action: The user has changed one of the default subs related to
* data, phone calls, or sms</p>
*