diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index a15caa09bb60..44842c62a3c8 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -2082,6 +2082,7 @@ public long getSize() {
/**
* Get the value set in {@link SessionParams#setOriginatingUri(Uri)}.
+ * Note: This value will only be non-null for the owner of the session.
*/
public @Nullable Uri getOriginatingUri() {
return originatingUri;
@@ -2096,6 +2097,7 @@ public int getOriginatingUid() {
/**
* Get the value set in {@link SessionParams#setReferrerUri(Uri)}
+ * Note: This value will only be non-null for the owner of the session.
*/
public @Nullable Uri getReferrerUri() {
return referrerUri;
diff --git a/core/res/res/values/colt_config.xml b/core/res/res/values/colt_config.xml
index 84d85900730a..9e29c10ea139 100644
--- a/core/res/res/values/colt_config.xml
+++ b/core/res/res/values/colt_config.xml
@@ -183,4 +183,12 @@
1
1
+
+ false
+
+
+ 0
+
diff --git a/core/res/res/values/colt_symbols.xml b/core/res/res/values/colt_symbols.xml
index a6f86e33d721..f7b0cc543d0d 100644
--- a/core/res/res/values/colt_symbols.xml
+++ b/core/res/res/values/colt_symbols.xml
@@ -237,6 +237,10 @@
+
+
+
+
diff --git a/core/tests/bugreports/src/android/server/bugreports/BugreportManagerTest.java b/core/tests/bugreports/src/android/server/bugreports/BugreportManagerTest.java
index c72707db9560..153337727e96 100644
--- a/core/tests/bugreports/src/android/server/bugreports/BugreportManagerTest.java
+++ b/core/tests/bugreports/src/android/server/bugreports/BugreportManagerTest.java
@@ -58,6 +58,8 @@ public class BugreportManagerTest {
private Handler mHandler;
private Executor mExecutor;
private BugreportManager mBrm;
+ private File mBugreportFile;
+ private File mScreenshotFile;
private ParcelFileDescriptor mBugreportFd;
private ParcelFileDescriptor mScreenshotFd;
@@ -73,8 +75,10 @@ public void setup() throws Exception {
};
mBrm = getBugreportManager();
- mBugreportFd = parcelFd("bugreport_" + name.getMethodName(), ".zip");
- mScreenshotFd = parcelFd("screenshot_" + name.getMethodName(), ".png");
+ mBugreportFile = createTempFile("bugreport_" + name.getMethodName(), ".zip");
+ mScreenshotFile = createTempFile("screenshot_" + name.getMethodName(), ".png");
+ mBugreportFd = parcelFd(mBugreportFile);
+ mScreenshotFd = parcelFd(mScreenshotFile);
getPermissions();
}
@@ -120,6 +124,21 @@ public void normalFlow_interactive() throws Exception {
assertFdsAreClosed(mBugreportFd);
}
+ @Test
+ public void normalFlow_full() throws Exception {
+ BugreportCallbackImpl callback = new BugreportCallbackImpl();
+ mBrm.startBugreport(mBugreportFd, mScreenshotFd, full(), mExecutor, callback);
+
+ waitTillDoneOrTimeout(callback);
+ assertThat(callback.isDone()).isTrue();
+ assertThat(callback.getErrorCode()).isEqualTo(
+ BugreportCallback.BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT);
+ // bugreport and screenshot files should be empty when user consent timed out.
+ assertThat(mBugreportFile.length()).isEqualTo(0);
+ assertThat(mScreenshotFile.length()).isEqualTo(0);
+ assertFdsAreClosed(mBugreportFd, mScreenshotFd);
+ }
+
@Test
public void simultaneousBugreportsNotAllowed() throws Exception {
// Start bugreport #1
@@ -129,9 +148,10 @@ public void simultaneousBugreportsNotAllowed() throws Exception {
// Before #1 is done, try to start #2.
assertThat(callback.isDone()).isFalse();
BugreportCallbackImpl callback2 = new BugreportCallbackImpl();
- ParcelFileDescriptor bugreportFd2 = parcelFd("bugreport_2_" + name.getMethodName(), ".zip");
- ParcelFileDescriptor screenshotFd2 =
- parcelFd("screenshot_2_" + name.getMethodName(), ".png");
+ File bugreportFile2 = createTempFile("bugreport_2_" + name.getMethodName(), ".zip");
+ File screenshotFile2 = createTempFile("screenshot_2_" + name.getMethodName(), ".png");
+ ParcelFileDescriptor bugreportFd2 = parcelFd(bugreportFile2);
+ ParcelFileDescriptor screenshotFd2 = parcelFd(screenshotFile2);
mBrm.startBugreport(bugreportFd2, screenshotFd2, wifi(), mExecutor, callback2);
Thread.sleep(500 /* .5s */);
@@ -271,12 +291,16 @@ public static BugreportManager getBugreportManager() {
return bm;
}
- private static ParcelFileDescriptor parcelFd(String prefix, String extension) throws Exception {
- File f = File.createTempFile(prefix, extension);
+ private static File createTempFile(String prefix, String extension) throws Exception {
+ final File f = File.createTempFile(prefix, extension);
f.setReadable(true, true);
f.setWritable(true, true);
+ f.deleteOnExit();
+ return f;
+ }
- return ParcelFileDescriptor.open(f,
+ private static ParcelFileDescriptor parcelFd(File file) throws Exception {
+ return ParcelFileDescriptor.open(file,
ParcelFileDescriptor.MODE_WRITE_ONLY | ParcelFileDescriptor.MODE_APPEND);
}
@@ -342,4 +366,13 @@ private static BugreportParams wifi() {
private static BugreportParams interactive() {
return new BugreportParams(BugreportParams.BUGREPORT_MODE_INTERACTIVE);
}
+
+ /*
+ * Returns a {@link BugreportParams} for full bugreport that includes a screenshot.
+ *
+ *
This can take on the order of minutes to finish
+ */
+ private static BugreportParams full() {
+ return new BugreportParams(BugreportParams.BUGREPORT_MODE_FULL);
+ }
}
diff --git a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java
index 325eb17342e1..a6f3006f3366 100644
--- a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java
+++ b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java
@@ -18,7 +18,6 @@
import android.app.Notification;
import android.app.NotificationManager;
-import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -392,13 +391,9 @@ private synchronized void setNiNotification(GpsNiNotification notif) {
mNiNotificationBuilder.setDefaults(0);
}
- // if not to popup dialog immediately, pending intent will open the dialog
- Intent intent = !mPopupImmediately ? getDlgIntent(notif) : new Intent();
- PendingIntent pi = PendingIntent.getBroadcast(mContext, 0, intent, 0);
mNiNotificationBuilder.setTicker(getNotifTicker(notif, mContext))
.setContentTitle(title)
- .setContentText(message)
- .setContentIntent(pi);
+ .setContentText(message);
notificationManager.notifyAsUser(null, notif.notificationId, mNiNotificationBuilder.build(),
UserHandle.ALL);
diff --git a/packages/SystemUI/res/drawable/dialog_tri_state_down_bg.xml b/packages/SystemUI/res/drawable/dialog_tri_state_down_bg.xml
new file mode 100644
index 000000000000..7dddc9d0e930
--- /dev/null
+++ b/packages/SystemUI/res/drawable/dialog_tri_state_down_bg.xml
@@ -0,0 +1,29 @@
+
+
+
+ -
+
+
+
+
+
+
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/dialog_tri_state_middle_bg.xml b/packages/SystemUI/res/drawable/dialog_tri_state_middle_bg.xml
new file mode 100644
index 000000000000..7cde6be2808c
--- /dev/null
+++ b/packages/SystemUI/res/drawable/dialog_tri_state_middle_bg.xml
@@ -0,0 +1,29 @@
+
+
+
+ -
+
+
+
+
+
+
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/dialog_tri_state_navigation_bg.xml b/packages/SystemUI/res/drawable/dialog_tri_state_navigation_bg.xml
new file mode 100644
index 000000000000..93011a323a5b
--- /dev/null
+++ b/packages/SystemUI/res/drawable/dialog_tri_state_navigation_bg.xml
@@ -0,0 +1,29 @@
+
+
+
+ -
+
+
+
+
+
+
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/dialog_tri_state_triangle_right.xml b/packages/SystemUI/res/drawable/dialog_tri_state_triangle_right.xml
new file mode 100644
index 000000000000..ab90683bea54
--- /dev/null
+++ b/packages/SystemUI/res/drawable/dialog_tri_state_triangle_right.xml
@@ -0,0 +1,27 @@
+
+
+
+ -
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/dialog_tri_state_triangle_top.xml b/packages/SystemUI/res/drawable/dialog_tri_state_triangle_top.xml
new file mode 100644
index 000000000000..e8566465d61b
--- /dev/null
+++ b/packages/SystemUI/res/drawable/dialog_tri_state_triangle_top.xml
@@ -0,0 +1,27 @@
+
+
+
+ -
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/dialog_tri_state_up_bg.xml b/packages/SystemUI/res/drawable/dialog_tri_state_up_bg.xml
new file mode 100644
index 000000000000..69757a77ee86
--- /dev/null
+++ b/packages/SystemUI/res/drawable/dialog_tri_state_up_bg.xml
@@ -0,0 +1,29 @@
+
+
+
+ -
+
+
+
+
+
+
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/tri_state_dialog.xml b/packages/SystemUI/res/layout/tri_state_dialog.xml
new file mode 100644
index 000000000000..177ed9b80521
--- /dev/null
+++ b/packages/SystemUI/res/layout/tri_state_dialog.xml
@@ -0,0 +1,62 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/packages/SystemUI/res/values/colt_dimens.xml b/packages/SystemUI/res/values/colt_dimens.xml
index 1884acf4cf09..7e43e9a11aac 100644
--- a/packages/SystemUI/res/values/colt_dimens.xml
+++ b/packages/SystemUI/res/values/colt_dimens.xml
@@ -88,4 +88,36 @@
36dp
+
+ 8.0dip
+ 21.0px
+ 423.0px
+ 270.375px
+ 296.0px
+ 270.375px
+ 165.0px
+ - @dimen/tri_state_down_dialog_padding_edge_deep
+ - @dimen/tri_state_down_dialog_padding_edge_deep
+ 270.375px
+ 2.0dip
+ 126.0px
+ 63.0px
+ 126.0px
+ 14.0px
+ 34.125px
+ 189.0px
+ 63.0px
+ 63.0px
+ 63.0px
+ 63.0px
+ 0.0px
+ 63.0px
+ 63.0px
+ 63.0px
+ 63.0px
+ 63.0px
+ 0.0px
+ 63.0px
+ 63.0px
+
diff --git a/packages/SystemUI/res/values/colt_styles.xml b/packages/SystemUI/res/values/colt_styles.xml
index 725519e977a2..aed47445df7c 100644
--- a/packages/SystemUI/res/values/colt_styles.xml
+++ b/packages/SystemUI/res/values/colt_styles.xml
@@ -52,4 +52,10 @@
- @*android:color/accent_device_default_light
- false
+
+
+
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
index 06c7940b67c3..44e480adca96 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
@@ -547,7 +547,7 @@ private Notification createSaveNotification(Uri uri) {
this,
REQUEST_CODE,
viewIntent,
- Intent.FLAG_GRANT_READ_URI_PERMISSION))
+ PendingIntent.FLAG_IMMUTABLE))
.addAction(shareAction)
.addAction(deleteAction)
.setAutoCancel(true);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index 969e94678055..ab639a0e9db0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -577,7 +577,7 @@ public NotificationStackScrollLayout(
res.getBoolean(R.bool.config_fadeNotificationsOnDismiss);
mRoundnessManager.setAnimatedChildren(mChildrenToAddAnimated);
mRoundnessManager.setOnRoundingChangedCallback(this::invalidate);
- addOnExpandedHeightChangedListener(mRoundnessManager::setExpanded);
+ addOnExpandedHeightListener(mRoundnessManager::setExpanded);
mLockscreenUserManager.addUserChangedListener(userId ->
updateSensitiveness(false /* animated */));
setOutlineProvider(mOutlineProvider);
@@ -585,7 +585,7 @@ public NotificationStackScrollLayout(
// Blocking helper manager wants to know the expanded state, update as well.
NotificationBlockingHelperManager blockingHelperManager =
Dependency.get(NotificationBlockingHelperManager.class);
- addOnExpandedHeightChangedListener((height, unused) -> {
+ addOnExpandedHeightListener((height, unused) -> {
blockingHelperManager.setNotificationShadeExpanded(height);
});
@@ -5470,7 +5470,7 @@ public boolean isFullyHidden() {
* @param listener the listener to notify.
*/
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
- public void addOnExpandedHeightChangedListener(BiConsumer listener) {
+ public void addOnExpandedHeightListener(BiConsumer listener) {
mExpandedHeightListeners.add(listener);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
index 08d34f1b27a5..59eafa409fd5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
@@ -139,7 +139,7 @@ public HeadsUpAppearanceController(
panelView.addTrackingHeadsUpListener(mSetTrackingHeadsUp);
panelView.addVerticalTranslationListener(mUpdatePanelTranslation);
panelView.setHeadsUpAppearanceController(this);
- mStackScroller.addOnExpandedHeightChangedListener(mSetExpandedHeight);
+ mStackScroller.addOnExpandedHeightListener(mSetExpandedHeight);
mStackScroller.addOnLayoutChangeListener(mStackScrollLayoutChangeListener);
mStackScroller.setHeadsUpAppearanceController(this);
mClockView = clockView;
diff --git a/packages/SystemUI/src/com/android/systemui/tristate/TriStateUiController.java b/packages/SystemUI/src/com/android/systemui/tristate/TriStateUiController.java
new file mode 100644
index 000000000000..203522132a3e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/tristate/TriStateUiController.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2019 CypherOS
+ * Copyright 2014-2019 Paranoid Android
+ *
+ * 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.systemui.tristate;
+
+import com.android.systemui.plugins.Plugin;
+import com.android.systemui.plugins.VolumeDialog.Callback;
+import com.android.systemui.plugins.annotations.DependsOn;
+import com.android.systemui.plugins.annotations.ProvidesInterface;
+
+@DependsOn(target = Callback.class)
+@ProvidesInterface(action = "com.android.systemui.action.PLUGIN_TRI_STATE_UI", version = 1)
+public interface TriStateUiController extends Plugin {
+
+ public interface UserActivityListener {
+ void onTriStateUserActivity();
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/tristate/TriStateUiControllerImpl.java b/packages/SystemUI/src/com/android/systemui/tristate/TriStateUiControllerImpl.java
new file mode 100644
index 000000000000..6d0f6359fdbc
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/tristate/TriStateUiControllerImpl.java
@@ -0,0 +1,476 @@
+/*
+ * Copyright (C) 2019 CypherOS
+ * Copyright 2014-2019 Paranoid Android
+ *
+ * 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.systemui.tristate;
+
+import static android.view.Surface.ROTATION_90;
+import static android.view.Surface.ROTATION_180;
+import static android.view.Surface.ROTATION_270;
+
+import android.app.Dialog;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.res.ColorStateList;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.graphics.drawable.ColorDrawable;
+import android.hardware.display.DisplayManagerGlobal;
+import android.media.AudioManager;
+import android.os.Build;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.provider.Settings;
+import android.util.Log;
+import android.view.Display;
+import android.view.OrientationEventListener;
+import android.view.ViewGroup;
+import android.view.Window;
+import android.view.WindowManager.LayoutParams;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.android.systemui.Dependency;
+import com.android.systemui.R;
+import com.android.systemui.tristate.TriStateUiController;
+import com.android.systemui.tristate.TriStateUiController.UserActivityListener;
+import com.android.systemui.plugins.VolumeDialogController;
+import com.android.systemui.plugins.VolumeDialogController.Callbacks;
+import com.android.systemui.plugins.VolumeDialogController.State;
+import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
+
+public class TriStateUiControllerImpl implements ConfigurationListener, TriStateUiController {
+
+ private static String TAG = "TriStateUiControllerImpl";
+
+ private static final int MSG_DIALOG_SHOW = 1;
+ private static final int MSG_DIALOG_DISMISS = 2;
+ private static final int MSG_RESET_SCHEDULE = 3;
+ private static final int MSG_STATE_CHANGE = 4;
+
+ private static final int MODE_NORMAL = AudioManager.RINGER_MODE_NORMAL;
+ private static final int MODE_SILENT = AudioManager.RINGER_MODE_SILENT;
+ private static final int MODE_VIBRATE = AudioManager.RINGER_MODE_VIBRATE;
+
+ private static final int TRI_STATE_UI_POSITION_LEFT = 0;
+ private static final int TRI_STATE_UI_POSITION_RIGHT = 1;
+
+ private static final int DIALOG_TIMEOUT = 2000;
+
+ private Context mContext;
+ private final VolumeDialogController mVolumeDialogController;
+ private final Callbacks mVolumeDialogCallback = new Callbacks() {
+ @Override
+ public void onShowRequested(int reason) { }
+
+ @Override
+ public void onDismissRequested(int reason) { }
+
+ @Override
+ public void onScreenOff() { }
+
+ @Override
+ public void onStateChanged(State state) { }
+
+ @Override
+ public void onLayoutDirectionChanged(int layoutDirection) { }
+
+ @Override
+ public void onShowVibrateHint() { }
+
+ @Override
+ public void onShowSilentHint() { }
+
+ @Override
+ public void onShowSafetyWarning(int flags) { }
+
+ @Override
+ public void onAccessibilityModeChanged(Boolean showA11yStream) { }
+
+ @Override
+ public void onCaptionComponentStateChanged(
+ Boolean isComponentEnabled, Boolean fromTooltip) {}
+
+ @Override
+ public void onConfigurationChanged() {
+ updateTheme();
+ updateTriStateLayout();
+ }
+ };
+
+ private int mDensity;
+ private Dialog mDialog;
+ private int mDialogPosition;
+ private ViewGroup mDialogView;
+ private final H mHandler;
+ private UserActivityListener mListener;
+ OrientationEventListener mOrientationListener;
+ private int mOrientationType = 0;
+ private boolean mShowing = false;
+ private int mBackgroundColor = 0;
+ private int mThemeMode = 0;
+ private int mIconColor = 0;
+ private int mTextColor = 0;
+ private ImageView mTriStateIcon;
+ private TextView mTriStateText;
+ private int mTriStateMode = -1;
+ private Window mWindow;
+ private LayoutParams mWindowLayoutParams;
+ private int mWindowType;
+
+ private final BroadcastReceiver mRingerStateReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ updateRingerModeChanged();
+ }
+ };
+
+ private final class H extends Handler {
+ private TriStateUiControllerImpl mUiController;
+
+ public H(TriStateUiControllerImpl uiController) {
+ super(Looper.getMainLooper());
+ mUiController = uiController;
+ }
+
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_DIALOG_SHOW:
+ mUiController.handleShow();
+ return;
+ case MSG_DIALOG_DISMISS:
+ mUiController.handleDismiss();
+ return;
+ case MSG_RESET_SCHEDULE:
+ mUiController.handleResetTimeout();
+ return;
+ case MSG_STATE_CHANGE:
+ mUiController.handleStateChanged();
+ return;
+ default:
+ return;
+ }
+ }
+ }
+
+ public TriStateUiControllerImpl(Context context) {
+ mContext = context;
+ mHandler = new H(this);
+ mOrientationListener = new OrientationEventListener(mContext, 3) {
+ @Override
+ public void onOrientationChanged(int orientation) {
+ checkOrientationType();
+ }
+ };
+ mVolumeDialogController = (VolumeDialogController) Dependency.get(VolumeDialogController.class);
+ IntentFilter ringerChanged = new IntentFilter(AudioManager.RINGER_MODE_CHANGED_ACTION);
+ mContext.registerReceiver(mRingerStateReceiver, ringerChanged);
+ }
+
+ private void checkOrientationType() {
+ Display display = DisplayManagerGlobal.getInstance().getRealDisplay(0);
+ if (display != null) {
+ int rotation = display.getRotation();
+ if (rotation != mOrientationType) {
+ mOrientationType = rotation;
+ updateTriStateLayout();
+ }
+ }
+ }
+
+ public void init(int windowType, UserActivityListener listener) {
+ mWindowType = windowType;
+ mDensity = mContext.getResources().getConfiguration().densityDpi;
+ mListener = listener;
+ ((ConfigurationController) Dependency.get(ConfigurationController.class)).addCallback(this);
+ mVolumeDialogController.addCallback(mVolumeDialogCallback, mHandler);
+ initDialog();
+ }
+
+ public void destroy() {
+ ((ConfigurationController) Dependency.get(ConfigurationController.class)).removeCallback(this);
+ mVolumeDialogController.removeCallback(mVolumeDialogCallback);
+ mContext.unregisterReceiver(mRingerStateReceiver);
+ }
+
+ private void initDialog() {
+ mDialog = new Dialog(mContext);
+ mShowing = false;
+ mWindow = mDialog.getWindow();
+ mWindow.requestFeature(Window.FEATURE_NO_TITLE);
+ mWindow.setBackgroundDrawable(new ColorDrawable(0));
+ mWindow.clearFlags(LayoutParams.FLAG_DIM_BEHIND);
+ mWindow.addFlags(LayoutParams.FLAG_NOT_FOCUSABLE
+ | LayoutParams.FLAG_LAYOUT_IN_SCREEN
+ | LayoutParams.FLAG_NOT_TOUCH_MODAL
+ | LayoutParams.FLAG_SHOW_WHEN_LOCKED
+ | LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
+ | LayoutParams.FLAG_HARDWARE_ACCELERATED);
+ mDialog.setCanceledOnTouchOutside(false);
+ mWindowLayoutParams = mWindow.getAttributes();
+ mWindowLayoutParams.type = mWindowType;
+ mWindowLayoutParams.format = -3;
+ mWindowLayoutParams.setTitle(TriStateUiControllerImpl.class.getSimpleName());
+ mWindowLayoutParams.gravity = 53;
+ mWindowLayoutParams.y = mDialogPosition;
+ mWindow.setAttributes(mWindowLayoutParams);
+ mWindow.setSoftInputMode(LayoutParams.SOFT_INPUT_ADJUST_NOTHING);
+ mDialog.setContentView(R.layout.tri_state_dialog);
+ mDialogView = (ViewGroup) mDialog.findViewById(R.id.tri_state_layout);
+ mTriStateIcon = (ImageView) mDialog.findViewById(R.id.tri_state_icon);
+ mTriStateText = (TextView) mDialog.findViewById(R.id.tri_state_text);
+ updateTheme();
+ }
+
+ public void show() {
+ mHandler.obtainMessage(MSG_DIALOG_SHOW, 0, 0).sendToTarget();
+ }
+
+ private void registerOrientationListener(boolean enable) {
+ if (mOrientationListener.canDetectOrientation() && enable) {
+ Log.v(TAG, "Can detect orientation");
+ mOrientationListener.enable();
+ return;
+ }
+ Log.v(TAG, "Cannot detect orientation");
+ mOrientationListener.disable();
+ }
+
+ private void updateTriStateLayout() {
+ if (mContext != null) {
+ int iconId = 0;
+ int textId = 0;
+ int bg = 0;
+ Resources res = mContext.getResources();
+ if (res != null) {
+ int positionY;
+ int positionY2 = mWindowLayoutParams.y;
+ int positionX = mWindowLayoutParams.x;
+ int gravity = mWindowLayoutParams.gravity;
+ switch (mTriStateMode) {
+ case MODE_SILENT:
+ iconId = R.drawable.ic_volume_ringer_mute;
+ textId = R.string.volume_ringer_status_silent;
+ break;
+ case MODE_VIBRATE:
+ iconId = R.drawable.ic_volume_ringer_vibrate;
+ textId = R.string.volume_ringer_status_vibrate;
+ break;
+ case MODE_NORMAL:
+ iconId = R.drawable.ic_volume_ringer;
+ textId = R.string.volume_ringer_status_normal;
+ break;
+ }
+ int triStatePos = res.getInteger(com.android.internal.R.integer.config_alertSliderLocation);
+ boolean isTsKeyRight = true;
+ if (triStatePos == TRI_STATE_UI_POSITION_LEFT) {
+ isTsKeyRight = false;
+ } else if (triStatePos == TRI_STATE_UI_POSITION_RIGHT) {
+ isTsKeyRight = true;
+ }
+ switch (mOrientationType) {
+ case ROTATION_90:
+ if (isTsKeyRight) {
+ gravity = 51;
+ } else {
+ gravity = 83;
+ }
+ positionY2 = res.getDimensionPixelSize(R.dimen.tri_state_up_dialog_position_deep_land);
+ if (isTsKeyRight) {
+ positionY2 += res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height);
+ }
+ if (mTriStateMode == MODE_SILENT) {
+ positionX = res.getDimensionPixelSize(R.dimen.tri_state_up_dialog_position_l);
+ } else if (mTriStateMode == MODE_VIBRATE) {
+ positionX = res.getDimensionPixelSize(R.dimen.tri_state_middle_dialog_position_l);
+ } else if (mTriStateMode == MODE_NORMAL) {
+ positionX = res.getDimensionPixelSize(R.dimen.tri_state_down_dialog_position_l);
+ }
+ bg = R.drawable.dialog_tri_state_middle_bg;
+ break;
+ case ROTATION_180:
+ if (isTsKeyRight) {
+ gravity = 83;
+ } else {
+ gravity = 85;
+ }
+ positionX = res.getDimensionPixelSize(R.dimen.tri_state_up_dialog_position_deep);
+ if (mTriStateMode != MODE_SILENT) {
+ if (mTriStateMode != MODE_VIBRATE) {
+ if (mTriStateMode == MODE_NORMAL) {
+ positionY = res.getDimensionPixelSize(R.dimen.tri_state_down_dialog_position) + res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height);
+ }
+ bg = R.drawable.dialog_tri_state_middle_bg;
+ break;
+ }
+ positionY = res.getDimensionPixelSize(R.dimen.tri_state_middle_dialog_position) + res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height);
+ } else {
+ positionY = res.getDimensionPixelSize(R.dimen.tri_state_up_dialog_position) + res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height);
+ }
+ positionY2 = positionY;
+ bg = R.drawable.dialog_tri_state_middle_bg;
+ case ROTATION_270:
+ if (isTsKeyRight) {
+ gravity = 85;
+ } else {
+ gravity = 53;
+ }
+ positionY2 = res.getDimensionPixelSize(R.dimen.tri_state_up_dialog_position_deep_land);
+ if (!isTsKeyRight) {
+ positionY2 += res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height);
+ }
+ if (mTriStateMode == MODE_SILENT) {
+ positionX = res.getDimensionPixelSize(R.dimen.tri_state_up_dialog_position_l);
+ } else if (mTriStateMode == MODE_VIBRATE) {
+ positionX = res.getDimensionPixelSize(R.dimen.tri_state_middle_dialog_position_l);
+ } else if (mTriStateMode == MODE_NORMAL) {
+ positionX = res.getDimensionPixelSize(R.dimen.tri_state_down_dialog_position_l);
+ }
+ bg = R.drawable.dialog_tri_state_middle_bg;
+ break;
+ default:
+ if (isTsKeyRight) {
+ gravity = 53;
+ } else {
+ gravity = 51;
+ }
+ positionX = res.getDimensionPixelSize(R.dimen.tri_state_up_dialog_position_deep);
+ if (mTriStateMode != MODE_SILENT) {
+ if (mTriStateMode != MODE_VIBRATE) {
+ if (mTriStateMode == MODE_NORMAL) {
+ positionY2 = res.getDimensionPixelSize(R.dimen.tri_state_down_dialog_position) + res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height);
+ bg = R.drawable.dialog_tri_state_down_bg;
+ break;
+ }
+ }
+ positionY2 = res.getDimensionPixelSize(R.dimen.tri_state_middle_dialog_position) + res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height);
+ bg = R.drawable.dialog_tri_state_middle_bg;
+ break;
+ }
+ positionY2 = res.getDimensionPixelSize(R.dimen.tri_state_up_dialog_position) + res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height);
+ bg = R.drawable.dialog_tri_state_up_bg;
+ break;
+ }
+ if (mTriStateMode != -1) {
+ if (mTriStateIcon != null) {
+ mTriStateIcon.setImageResource(iconId);
+ }
+ if (mTriStateText != null) {
+ String inputText = res.getString(textId);
+ if (inputText != null && mTriStateText.length() == inputText.length()) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(inputText);
+ sb.append(" ");
+ inputText = sb.toString();
+ }
+ mTriStateText.setText(inputText);
+ }
+ if (mDialogView != null) {
+ mDialogView.setBackgroundDrawable(res.getDrawable(bg));
+ }
+ mDialogPosition = positionY2;
+ }
+ positionY = res.getDimensionPixelSize(R.dimen.tri_state_dialog_padding);
+ mWindowLayoutParams.gravity = gravity;
+ mWindowLayoutParams.y = positionY2 - positionY;
+ mWindowLayoutParams.x = positionX - positionY;
+ mWindow.setAttributes(mWindowLayoutParams);
+ handleResetTimeout();
+ }
+ }
+ }
+
+ private void updateRingerModeChanged() {
+ mHandler.obtainMessage(MSG_STATE_CHANGE, 0, 0).sendToTarget();
+ if (mTriStateMode != -1) {
+ show();
+ }
+ }
+
+ private void handleShow() {
+ mHandler.removeMessages(MSG_DIALOG_SHOW);
+ mHandler.removeMessages(MSG_DIALOG_DISMISS);
+ handleResetTimeout();
+ if (!mShowing) {
+ updateTheme();
+ registerOrientationListener(true);
+ checkOrientationType();
+ mShowing = true;
+ mDialog.show();
+ if (mListener != null) {
+ mListener.onTriStateUserActivity();
+ }
+ }
+ }
+
+ private void handleDismiss() {
+ mHandler.removeMessages(MSG_DIALOG_SHOW);
+ mHandler.removeMessages(MSG_DIALOG_DISMISS);
+ if (mShowing) {
+ registerOrientationListener(false);
+ mShowing = false;
+ mDialog.dismiss();
+ }
+ }
+
+ private void handleStateChanged() {
+ AudioManager am = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
+ int ringerMode = am.getRingerModeInternal();
+ if (ringerMode != mTriStateMode) {
+ mTriStateMode = ringerMode;
+ updateTriStateLayout();
+ if (mListener != null) {
+ mListener.onTriStateUserActivity();
+ }
+ }
+ }
+
+ public void handleResetTimeout() {
+ mHandler.removeMessages(MSG_DIALOG_DISMISS);
+ mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_DIALOG_DISMISS, MSG_RESET_SCHEDULE, 0), (long) DIALOG_TIMEOUT);
+ if (mListener != null) {
+ mListener.onTriStateUserActivity();
+ }
+ }
+
+ @Override
+ public void onDensityOrFontScaleChanged() {
+ handleDismiss();
+ initDialog();
+ updateTriStateLayout();
+ }
+
+ private void updateTheme() {
+ // Todo: Add some logic to update the theme only when a new theme is applied
+ mIconColor = getAttrColor(android.R.attr.colorAccent);
+ mTextColor = getAttrColor(android.R.attr.textColorPrimary);
+ mBackgroundColor = getAttrColor(android.R.attr.colorPrimary);
+ mDialogView.setBackgroundTintList(ColorStateList.valueOf(mBackgroundColor));
+ mTriStateIcon.setColorFilter(mIconColor);
+ mTriStateText.setTextColor(mTextColor);
+ }
+
+ public int getAttrColor(int attr) {
+ TypedArray ta = mContext.obtainStyledAttributes(new int[]{attr});
+ int colorAccent = ta.getColor(0, 0);
+ ta.recycle();
+ return colorAccent;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/util/leak/LeakReporter.java b/packages/SystemUI/src/com/android/systemui/util/leak/LeakReporter.java
index b25df5f9c07f..5e7280840bb9 100644
--- a/packages/SystemUI/src/com/android/systemui/util/leak/LeakReporter.java
+++ b/packages/SystemUI/src/com/android/systemui/util/leak/LeakReporter.java
@@ -104,9 +104,13 @@ public void dumpLeak(int garbageCount) {
.setContentText(String.format(
"SystemUI has detected %d leaked objects. Tap to send", garbageCount))
.setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
- .setContentIntent(PendingIntent.getActivityAsUser(mContext, 0,
+ .setContentIntent(PendingIntent.getActivityAsUser(
+ mContext,
+ 0,
getIntent(hprofFile, dumpFile),
- PendingIntent.FLAG_UPDATE_CURRENT, null, UserHandle.CURRENT));
+ PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE,
+ null,
+ UserHandle.CURRENT));
notiMan.notify(TAG, 0, builder.build());
} catch (IOException e) {
Log.e(TAG, "Couldn't dump heap for leak", e);
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java
index d2f185a88bfd..55de6c8bd8af 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java
@@ -28,6 +28,8 @@
import com.android.settingslib.applications.InterestingConfigChanges;
import com.android.systemui.Dependency;
import com.android.systemui.SystemUI;
+import com.android.systemui.tristate.TriStateUiController;
+import com.android.systemui.tristate.TriStateUiControllerImpl;
import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.PluginDependencyProvider;
@@ -44,7 +46,7 @@
* Implementation of VolumeComponent backed by the new volume dialog.
*/
public class VolumeDialogComponent implements VolumeComponent, TunerService.Tunable,
- VolumeDialogControllerImpl.UserActivityListener{
+ VolumeDialogControllerImpl.UserActivityListener, TriStateUiController.UserActivityListener {
public static final String VOLUME_DOWN_SILENT = "sysui_volume_down_silent";
public static final String VOLUME_UP_SILENT = "sysui_volume_up_silent";
@@ -57,6 +59,7 @@ public class VolumeDialogComponent implements VolumeComponent, TunerService.Tuna
private final SystemUI mSysui;
protected final Context mContext;
private final VolumeDialogControllerImpl mController;
+ private TriStateUiControllerImpl mTriStateController;
private final InterestingConfigChanges mConfigChanges = new InterestingConfigChanges(
ActivityInfo.CONFIG_FONT_SCALE | ActivityInfo.CONFIG_LOCALE
| ActivityInfo.CONFIG_ASSETS_PATHS | ActivityInfo.CONFIG_UI_MODE);
@@ -73,6 +76,8 @@ public VolumeDialogComponent(SystemUI sysui, Context context) {
mContext = context;
mController = (VolumeDialogControllerImpl) Dependency.get(VolumeDialogController.class);
mController.setUserActivityListener(this);
+ boolean hasAlertSlider = mContext.getResources().
+ getBoolean(com.android.internal.R.bool.config_hasAlertSlider);
// Allow plugins to reference the VolumeDialogController.
Dependency.get(PluginDependencyProvider.class)
.allowPluginDependency(VolumeDialogController.class);
@@ -85,6 +90,13 @@ public VolumeDialogComponent(SystemUI sysui, Context context) {
}
mDialog = dialog;
mDialog.init(LayoutParams.TYPE_VOLUME_OVERLAY, mVolumeDialogCallback);
+ if (hasAlertSlider) {
+ if (mTriStateController != null) {
+ mTriStateController.destroy();
+ }
+ mTriStateController = new TriStateUiControllerImpl(mContext);
+ mTriStateController.init(LayoutParams.TYPE_VOLUME_OVERLAY, this);
+ }
}).build();
applyConfiguration();
Dependency.get(TunerService.class).addTunable(this, VOLUME_DOWN_SILENT, VOLUME_UP_SILENT,
@@ -176,6 +188,11 @@ private void startSettings(Intent intent) {
true /* onlyProvisioned */, true /* dismissShade */);
}
+ @Override
+ public void onTriStateUserActivity() {
+ onUserActivity();
+ }
+
private final VolumeDialogImpl.Callback mVolumeDialogCallback = new VolumeDialogImpl.Callback() {
@Override
public void onZenSettingsClicked() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java
index 5d09d3905e34..0937a568c140 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java
@@ -33,6 +33,8 @@
import static java.lang.Thread.sleep;
+import static java.lang.Thread.sleep;
+
import android.app.AppOpsManager;
import android.content.pm.PackageManager;
import android.os.UserHandle;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
index 7c9537b95319..079eaa2b0fda 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
@@ -120,7 +120,6 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
@Mock private NotificationIconAreaController mNotificationIconAreaController;
@Mock private MetricsLogger mMetricsLogger;
@Mock private NotificationRoundnessManager mNotificationRoundnessManager;
- @Mock private KeyguardBypassController mKeyguardBypassController;
@Mock private NotificationLockscreenUserManager mLockscreenUserManager;
private UserChangedListener mUserChangedListener;
private TestableNotificationEntryManager mEntryManager;
@@ -141,9 +140,9 @@ public void setUp() throws Exception {
mDependency.injectTestDependency(
NotificationBlockingHelperManager.class,
mBlockingHelperManager);
- mDependency.injectTestDependency(SysuiStatusBarStateController.class, mBarState);
mDependency.injectTestDependency(NotificationLockscreenUserManager.class,
mLockscreenUserManager);
+ mDependency.injectTestDependency(StatusBarStateController.class, mBarState);
mDependency.injectTestDependency(MetricsLogger.class, mMetricsLogger);
mDependency.injectTestDependency(NotificationRemoteInputManager.class,
mRemoteInputManager);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index ff84688654a9..a210749ee99c 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -3235,6 +3235,10 @@ public int getPackageProcessState(String packageName, String callingPackage) {
@Override
public boolean setProcessMemoryTrimLevel(String process, int userId, int level)
throws RemoteException {
+ if (!isCallerShell()) {
+ EventLog.writeEvent(0x534e4554, 160390416, Binder.getCallingUid(), "");
+ throw new SecurityException("Only shell can call it");
+ }
synchronized (this) {
final ProcessRecord app = findProcessLocked(process, userId, "setProcessMemoryTrimLevel");
if (app == null) {
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 687ca1927882..01f6b22ebc67 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -521,10 +521,6 @@ private void updateAccessTimeAndDuration(long time, long duration,
private void updateProxyState(long key, int proxyUid,
@Nullable String proxyPackageName) {
- if (proxyUid == Process.INVALID_UID) {
- return;
- }
-
if (mProxyUids == null) {
mProxyUids = new LongSparseLongArray();
}
@@ -720,12 +716,7 @@ public String toString() {
public void binderDied() {
synchronized (AppOpsService.this) {
for (int i=mStartedOps.size()-1; i>=0; i--) {
- final Op op = mStartedOps.get(i);
- finishOperationLocked(op, /*finishNested*/ true);
- if (op.startNesting <= 0) {
- scheduleOpActiveChangedIfNeededLocked(op.op, op.uidState.uid,
- op.packageName, false);
- }
+ finishOperationLocked(mStartedOps.get(i), /*finishNested*/ true);
}
mClients.remove(mAppToken);
}
@@ -1131,8 +1122,8 @@ public List getOpsForPackage(int uid, String packageNa
return Collections.emptyList();
}
synchronized (this) {
- Ops pkgOps = getOpsRawLocked(uid, resolvedPackageName, false /* isPrivileged */,
- false /* edit */);
+ Ops pkgOps = getOpsRawLocked(uid, resolvedPackageName, false /* edit */,
+ false /* uidMismatchExpected */);
if (pkgOps == null) {
return null;
}
@@ -1229,7 +1220,8 @@ public List getUidOps(int uid, int[] ops) {
private void pruneOp(Op op, int uid, String packageName) {
if (!op.hasAnyTime()) {
- Ops ops = getOpsRawLocked(uid, packageName, false /* isPrivileged */, false /* edit */);
+ Ops ops = getOpsRawLocked(uid, packageName, false /* edit */,
+ false /* uidMismatchExpected */);
if (ops != null) {
ops.remove(op.op);
if (ops.size() <= 0) {
@@ -1446,6 +1438,11 @@ private void setAllPkgModesToDefault(int code, int uid) {
}
}
+ @Override
+ public void setMode(int code, int uid, String packageName, int mode) {
+ setMode(code, uid, packageName, mode, true, false);
+ }
+
/**
* Sets the mode for a certain op and uid.
*
@@ -1453,25 +1450,19 @@ private void setAllPkgModesToDefault(int code, int uid) {
* @param uid The UID for which to set
* @param packageName The package for which to set
* @param mode The new mode to set
+ * @param verifyUid Iff {@code true}, check that the package name belongs to the uid
+ * @param isPrivileged Whether the package is privileged. (Only used if {@code verifyUid ==
+ * false})
*/
- @Override
- public void setMode(int code, int uid, @NonNull String packageName, int mode) {
+ private void setMode(int code, int uid, @NonNull String packageName, int mode,
+ boolean verifyUid, boolean isPrivileged) {
enforceManageAppOpsModes(Binder.getCallingPid(), Binder.getCallingUid(), uid);
verifyIncomingOp(code);
ArraySet repCbs = null;
code = AppOpsManager.opToSwitch(code);
-
- boolean isPrivileged;
- try {
- isPrivileged = verifyAndGetIsPrivileged(uid, packageName);
- } catch (SecurityException e) {
- Slog.e(TAG, "Cannot setMode", e);
- return;
- }
-
synchronized (this) {
UidState uidState = getUidStateLocked(uid, false);
- Op op = getOpLocked(code, uid, packageName, isPrivileged, true);
+ Op op = getOpLocked(code, uid, packageName, true, verifyUid, isPrivileged);
if (op != null) {
if (op.mode != mode) {
op.mode = mode;
@@ -1836,6 +1827,14 @@ private int checkOperationImpl(int code, int uid, String packageName,
return checkOperationUnchecked(code, uid, resolvedPackageName, raw);
}
+ /**
+ * @see #checkOperationUnchecked(int, int, String, boolean, boolean)
+ */
+ private @Mode int checkOperationUnchecked(int code, int uid, @NonNull String packageName,
+ boolean raw) {
+ return checkOperationUnchecked(code, uid, packageName, raw, true);
+ }
+
/**
* Get the mode of an app-op.
*
@@ -1843,26 +1842,20 @@ private int checkOperationImpl(int code, int uid, String packageName,
* @param uid The uid of the package the op belongs to
* @param packageName The package the op belongs to
* @param raw If the raw state of eval-ed state should be checked.
+ * @param verify If the code should check the package belongs to the uid
*
* @return The mode of the op
*/
private @Mode int checkOperationUnchecked(int code, int uid, @NonNull String packageName,
- boolean raw) {
+ boolean raw, boolean verify) {
if (isOpRestrictedDueToSuspend(code, packageName, uid)) {
return AppOpsManager.MODE_IGNORED;
}
-
- boolean isPrivileged;
-
- try {
- isPrivileged = verifyAndGetIsPrivileged(uid, packageName);
- } catch (SecurityException e) {
- Slog.e(TAG, "checkOperation", e);
- return AppOpsManager.opToDefaultMode(code);
- }
-
synchronized (this) {
- if (isOpRestrictedLocked(uid, code, packageName, isPrivileged)) {
+ if (verify) {
+ checkPackage(uid, packageName);
+ }
+ if (isOpRestrictedLocked(uid, code, packageName)) {
return AppOpsManager.MODE_IGNORED;
}
code = AppOpsManager.opToSwitch(code);
@@ -1872,7 +1865,7 @@ private int checkOperationImpl(int code, int uid, String packageName,
final int rawMode = uidState.opModes.get(code);
return raw ? rawMode : uidState.evalMode(code, rawMode);
}
- Op op = getOpLocked(code, uid, packageName, false, false);
+ Op op = getOpLocked(code, uid, packageName, false, verify, false);
if (op == null) {
return AppOpsManager.opToDefaultMode(code);
}
@@ -1977,12 +1970,14 @@ public void setAudioRestriction(int code, int usage, int uid, int mode,
@Override
public int checkPackage(int uid, String packageName) {
Preconditions.checkNotNull(packageName);
- try {
- verifyAndGetIsPrivileged(uid, packageName);
-
- return AppOpsManager.MODE_ALLOWED;
- } catch (SecurityException ignored) {
- return AppOpsManager.MODE_ERRORED;
+ synchronized (this) {
+ Ops ops = getOpsRawLocked(uid, packageName, true /* edit */,
+ true /* uidMismatchExpected */);
+ if (ops != null) {
+ return AppOpsManager.MODE_ALLOWED;
+ } else {
+ return AppOpsManager.MODE_ERRORED;
+ }
}
}
@@ -2045,16 +2040,9 @@ private int noteOperationImpl(int code, int uid, String packageName) {
private int noteOperationUnchecked(int code, int uid, String packageName,
int proxyUid, String proxyPackageName, @OpFlags int flags) {
- boolean isPrivileged;
- try {
- isPrivileged = verifyAndGetIsPrivileged(uid, packageName);
- } catch (SecurityException e) {
- Slog.e(TAG, "noteOperation", e);
- return AppOpsManager.MODE_ERRORED;
- }
-
synchronized (this) {
- final Ops ops = getOpsRawLocked(uid, packageName, isPrivileged, true /* edit */);
+ final Ops ops = getOpsRawLocked(uid, packageName, true /* edit */,
+ false /* uidMismatchExpected */);
if (ops == null) {
scheduleOpNotedIfNeededLocked(code, uid, packageName,
AppOpsManager.MODE_IGNORED);
@@ -2063,7 +2051,7 @@ private int noteOperationUnchecked(int code, int uid, String packageName,
return AppOpsManager.MODE_ERRORED;
}
final Op op = getOpLocked(ops, code, true);
- if (isOpRestrictedLocked(uid, code, packageName, isPrivileged)) {
+ if (isOpRestrictedLocked(uid, code, packageName)) {
scheduleOpNotedIfNeededLocked(code, uid, packageName,
AppOpsManager.MODE_IGNORED);
return AppOpsManager.MODE_IGNORED;
@@ -2222,25 +2210,16 @@ public int startOperation(IBinder token, int code, int uid, String packageName,
return AppOpsManager.MODE_IGNORED;
}
ClientState client = (ClientState)token;
-
- boolean isPrivileged;
- try {
- isPrivileged = verifyAndGetIsPrivileged(uid, packageName);
- } catch (SecurityException e) {
- Slog.e(TAG, "startOperation", e);
- return AppOpsManager.MODE_ERRORED;
- }
-
synchronized (this) {
- final Ops ops = getOpsRawLocked(uid, resolvedPackageName, isPrivileged,
- true /* edit */);
+ final Ops ops = getOpsRawLocked(uid, resolvedPackageName, true /* edit */,
+ false /* uidMismatchExpected */);
if (ops == null) {
if (DEBUG) Slog.d(TAG, "startOperation: no op for code " + code + " uid " + uid
+ " package " + resolvedPackageName);
return AppOpsManager.MODE_ERRORED;
}
final Op op = getOpLocked(ops, code, true);
- if (isOpRestrictedLocked(uid, code, resolvedPackageName, isPrivileged)) {
+ if (isOpRestrictedLocked(uid, code, resolvedPackageName)) {
return AppOpsManager.MODE_IGNORED;
}
final int switchCode = AppOpsManager.opToSwitch(code);
@@ -2312,17 +2291,8 @@ public void finishOperation(IBinder token, int code, int uid, String packageName
return;
}
ClientState client = (ClientState) token;
-
- boolean isPrivileged;
- try {
- isPrivileged = verifyAndGetIsPrivileged(uid, packageName);
- } catch (SecurityException e) {
- Slog.e(TAG, "Cannot finishOperation", e);
- return;
- }
-
synchronized (this) {
- Op op = getOpLocked(code, uid, resolvedPackageName, isPrivileged, true);
+ Op op = getOpLocked(code, uid, resolvedPackageName, true, true, false);
if (op == null) {
return;
}
@@ -2587,76 +2557,8 @@ private void commitUidPendingStateLocked(UidState uidState) {
uidState.pendingStateCommitTime = 0;
}
- /**
- * Verify that package belongs to uid and return whether the package is privileged.
- *
- * @param uid The uid the package belongs to
- * @param packageName The package the might belong to the uid
- *
- * @return {@code true} iff the package is privileged
- */
- private boolean verifyAndGetIsPrivileged(int uid, String packageName) {
- if (uid == Process.ROOT_UID) {
- // For backwards compatibility, don't check package name for root UID.
- return false;
- }
-
- // Do not check if uid/packageName is already known
- synchronized (this) {
- UidState uidState = mUidStates.get(uid);
- if (uidState != null && uidState.pkgOps != null) {
- Ops ops = uidState.pkgOps.get(packageName);
-
- if (ops != null) {
- return ops.isPrivileged;
- }
- }
- }
-
- boolean isPrivileged = false;
- final long ident = Binder.clearCallingIdentity();
- try {
- int pkgUid;
-
- ApplicationInfo appInfo = LocalServices.getService(PackageManagerInternal.class)
- .getApplicationInfo(packageName, PackageManager.MATCH_DIRECT_BOOT_AWARE
- | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
- | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS
- | PackageManager.MATCH_UNINSTALLED_PACKAGES
- | PackageManager.MATCH_INSTANT,
- Process.SYSTEM_UID, UserHandle.getUserId(uid));
- if (appInfo != null) {
- pkgUid = appInfo.uid;
- isPrivileged = (appInfo.privateFlags
- & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
- } else {
- pkgUid = resolveUid(packageName);
- if (pkgUid >= 0) {
- isPrivileged = false;
- }
- }
- if (pkgUid != uid) {
- throw new SecurityException("Specified package " + packageName + " under uid " + uid
- + " but it is really " + pkgUid);
- }
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
-
- return isPrivileged;
- }
-
- /**
- * Get (and potentially create) ops.
- *
- * @param uid The uid the package belongs to
- * @param packageName The name of the package
- * @param isPrivileged If the package is privilidged (ignored if {@code edit} is false)
- * @param edit If an ops does not exist, create the ops?
-
- * @return
- */
- private Ops getOpsRawLocked(int uid, String packageName, boolean isPrivileged, boolean edit) {
+ private Ops getOpsRawLocked(int uid, String packageName, boolean edit,
+ boolean uidMismatchExpected) {
UidState uidState = getUidStateLocked(uid, edit);
if (uidState == null) {
return null;
@@ -2674,6 +2576,47 @@ private Ops getOpsRawLocked(int uid, String packageName, boolean isPrivileged, b
if (!edit) {
return null;
}
+ boolean isPrivileged = false;
+ // This is the first time we have seen this package name under this uid,
+ // so let's make sure it is valid.
+ if (uid != 0) {
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ int pkgUid = -1;
+ try {
+ ApplicationInfo appInfo = ActivityThread.getPackageManager()
+ .getApplicationInfo(packageName,
+ PackageManager.MATCH_DIRECT_BOOT_AWARE
+ | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
+ UserHandle.getUserId(uid));
+ if (appInfo != null) {
+ pkgUid = appInfo.uid;
+ isPrivileged = (appInfo.privateFlags
+ & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
+ } else {
+ pkgUid = resolveUid(packageName);
+ if (pkgUid >= 0) {
+ isPrivileged = false;
+ }
+ }
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Could not contact PackageManager", e);
+ }
+ if (pkgUid != uid) {
+ // Oops! The package name is not valid for the uid they are calling
+ // under. Abort.
+ if (!uidMismatchExpected) {
+ RuntimeException ex = new RuntimeException("here");
+ ex.fillInStackTrace();
+ Slog.w(TAG, "Bad call: specified package " + packageName
+ + " under uid " + uid + " but it is really " + pkgUid, ex);
+ }
+ return null;
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
ops = new Ops(packageName, uidState, isPrivileged);
uidState.pkgOps.put(packageName, ops);
}
@@ -2681,7 +2624,7 @@ private Ops getOpsRawLocked(int uid, String packageName, boolean isPrivileged, b
}
/**
- * Get the state of all ops for a package.
+ * Get the state of all ops for a package, don't verify that package belongs to uid.
*
* Usually callers should use {@link #getOpLocked} and not call this directly.
*
@@ -2739,15 +2682,23 @@ private void scheduleFastWriteLocked() {
* @param code The code of the op
* @param uid The uid the of the package
* @param packageName The package name for which to get the state for
- * @param isPrivileged Whether the package is privileged or not (only used if {@code edit
- * == true})
* @param edit Iff {@code true} create the {@link Op} object if not yet created
+ * @param verifyUid Iff {@code true} check that the package belongs to the uid
+ * @param isPrivileged Whether the package is privileged or not (only used if {@code verifyUid
+ * == false})
*
* @return The {@link Op state} of the op
*/
- private @Nullable Op getOpLocked(int code, int uid, @NonNull String packageName,
- boolean isPrivileged, boolean edit) {
- Ops ops = getOpsRawNoVerifyLocked(uid, packageName, edit, isPrivileged);
+ private @Nullable Op getOpLocked(int code, int uid, @NonNull String packageName, boolean edit,
+ boolean verifyUid, boolean isPrivileged) {
+ Ops ops;
+
+ if (verifyUid) {
+ ops = getOpsRawLocked(uid, packageName, edit, false /* uidMismatchExpected */);
+ } else {
+ ops = getOpsRawNoVerifyLocked(uid, packageName, edit, isPrivileged);
+ }
+
if (ops == null) {
return null;
}
@@ -2777,8 +2728,7 @@ private boolean isOpRestrictedDueToSuspend(int code, String packageName, int uid
return pmi.isPackageSuspended(packageName, UserHandle.getUserId(uid));
}
- private boolean isOpRestrictedLocked(int uid, int code, String packageName,
- boolean isPrivileged) {
+ private boolean isOpRestrictedLocked(int uid, int code, String packageName) {
int userHandle = UserHandle.getUserId(uid);
final int restrictionSetCount = mOpUserRestrictions.size();
@@ -2790,8 +2740,8 @@ private boolean isOpRestrictedLocked(int uid, int code, String packageName,
if (AppOpsManager.opAllowSystemBypassRestriction(code)) {
// If we are the system, bypass user restrictions for certain codes
synchronized (this) {
- Ops ops = getOpsRawLocked(uid, packageName, isPrivileged,
- true /* edit */);
+ Ops ops = getOpsRawLocked(uid, packageName, true /* edit */,
+ false /* uidMismatchExpected */);
if ((ops != null) && ops.isPrivileged) {
return false;
}
@@ -3103,40 +3053,17 @@ void writeState() {
out.startTag(null, "app-ops");
out.attribute(null, "v", String.valueOf(CURRENT_VERSION));
- SparseArray uidStatesClone;
- synchronized (this) {
- uidStatesClone = new SparseArray<>(mUidStates.size());
-
- final int uidStateCount = mUidStates.size();
- for (int uidStateNum = 0; uidStateNum < uidStateCount; uidStateNum++) {
- UidState uidState = mUidStates.valueAt(uidStateNum);
- int uid = mUidStates.keyAt(uidStateNum);
-
- SparseIntArray opModes = uidState.opModes;
- if (opModes != null && opModes.size() > 0) {
- uidStatesClone.put(uid, new SparseIntArray(opModes.size()));
-
- final int opCount = opModes.size();
- for (int opCountNum = 0; opCountNum < opCount; opCountNum++) {
- uidStatesClone.get(uid).put(
- opModes.keyAt(opCountNum),
- opModes.valueAt(opCountNum));
- }
- }
- }
- }
-
- final int uidStateCount = uidStatesClone.size();
- for (int uidStateNum = 0; uidStateNum < uidStateCount; uidStateNum++) {
- SparseIntArray opModes = uidStatesClone.valueAt(uidStateNum);
- if (opModes != null && opModes.size() > 0) {
+ final int uidStateCount = mUidStates.size();
+ for (int i = 0; i < uidStateCount; i++) {
+ UidState uidState = mUidStates.valueAt(i);
+ if (uidState.opModes != null && uidState.opModes.size() > 0) {
out.startTag(null, "uid");
- out.attribute(null, "n",
- Integer.toString(uidStatesClone.keyAt(uidStateNum)));
- final int opCount = opModes.size();
- for (int opCountNum = 0; opCountNum < opCount; opCountNum++) {
- final int op = opModes.keyAt(opCountNum);
- final int mode = opModes.valueAt(opCountNum);
+ out.attribute(null, "n", Integer.toString(uidState.uid));
+ SparseIntArray uidOpModes = uidState.opModes;
+ final int opCount = uidOpModes.size();
+ for (int j = 0; j < opCount; j++) {
+ final int op = uidOpModes.keyAt(j);
+ final int mode = uidOpModes.valueAt(j);
out.startTag(null, "op");
out.attribute(null, "n", Integer.toString(op));
out.attribute(null, "m", Integer.toString(mode));
@@ -3162,7 +3089,7 @@ void writeState() {
out.attribute(null, "n", Integer.toString(pkg.getUid()));
synchronized (this) {
Ops ops = getOpsRawLocked(pkg.getUid(), pkg.getPackageName(),
- false /* isPrivileged */, false /* edit */);
+ false /* edit */, false /* uidMismatchExpected */);
// Should always be present as the list of PackageOps is generated
// from Ops.
if (ops != null) {
@@ -4740,9 +4667,18 @@ private final class AppOpsManagerInternalImpl extends AppOpsManagerInternal {
}
}
+ public void setUidMode(int code, int uid, int mode) {
+ AppOpsService.this.setUidMode(code, uid, mode);
+ }
+
@Override
public void setAllPkgModesToDefault(int code, int uid) {
AppOpsService.this.setAllPkgModesToDefault(code, uid);
}
+
+ public @Mode int checkOperationUnchecked(int code, int uid, @NonNull String packageName) {
+ return AppOpsService.this.checkOperationUnchecked(code, uid, packageName, true, false);
+ }
}
}
+
diff --git a/services/core/java/com/android/server/location/GnssVisibilityControl.java b/services/core/java/com/android/server/location/GnssVisibilityControl.java
index dd522b95a938..0f38473ef11a 100644
--- a/services/core/java/com/android/server/location/GnssVisibilityControl.java
+++ b/services/core/java/com/android/server/location/GnssVisibilityControl.java
@@ -21,7 +21,6 @@
import android.app.AppOpsManager;
import android.app.Notification;
import android.app.NotificationManager;
-import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -645,7 +644,6 @@ private static Notification createEmergencyLocationUserNotification(Context cont
.setTicker(accessibilityServicesText)
.setContentTitle(firstLineText)
.setContentText(secondLineText)
- .setContentIntent(PendingIntent.getBroadcast(context, 0, new Intent(), 0))
.build();
}
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 8227e58bf7e0..ba8376222b97 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -770,26 +770,30 @@ private String buildExternalStageCid(int sessionId) {
public SessionInfo getSessionInfo(int sessionId) {
synchronized (mSessions) {
final PackageInstallerSession session = mSessions.get(sessionId);
- return session != null ? session.generateInfo() : null;
+
+ return session != null
+ ? session.generateInfoForCaller(true /*withIcon*/, Binder.getCallingUid())
+ : null;
}
}
@Override
public ParceledListSlice getStagedSessions() {
- return mStagingManager.getSessions();
+ return mStagingManager.getSessions(Binder.getCallingUid());
}
@Override
public ParceledListSlice getAllSessions(int userId) {
+ final int callingUid = Binder.getCallingUid();
mPermissionManager.enforceCrossUserPermission(
- Binder.getCallingUid(), userId, true, false, "getAllSessions");
+ callingUid, userId, true, false, "getAllSessions");
final List result = new ArrayList<>();
synchronized (mSessions) {
for (int i = 0; i < mSessions.size(); i++) {
final PackageInstallerSession session = mSessions.valueAt(i);
if (session.userId == userId && !session.hasParentSessionId()) {
- result.add(session.generateInfo(false));
+ result.add(session.generateInfoForCaller(false, callingUid));
}
}
}
@@ -807,7 +811,8 @@ public ParceledListSlice getMySessions(String installerPackageName,
for (int i = 0; i < mSessions.size(); i++) {
final PackageInstallerSession session = mSessions.valueAt(i);
- SessionInfo info = session.generateInfo(false);
+ SessionInfo info =
+ session.generateInfoForCaller(false /*withIcon*/, Process.SYSTEM_UID);
if (Objects.equals(info.getInstallerPackageName(), installerPackageName)
&& session.userId == userId && !session.hasParentSessionId()) {
result.add(info);
@@ -1251,7 +1256,10 @@ public void onStagedSessionChanged(PackageInstallerSession session) {
session.markUpdated();
writeSessionsAsync();
if (mOkToSendBroadcasts) {
- mPm.sendSessionUpdatedBroadcast(session.generateInfo(false),
+ // we don't scrub the data here as this is sent only to the installer several
+ // privileged system packages
+ mPm.sendSessionUpdatedBroadcast(
+ session.generateInfoForCaller(false/*icon*/, Process.SYSTEM_UID),
session.userId);
}
}
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index b661a8553698..a421f8f27b91 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -457,11 +457,41 @@ public PackageInstallerSession(PackageInstallerService.InternalCallback callback
stagedSessionErrorMessage != null ? stagedSessionErrorMessage : "";
}
- public SessionInfo generateInfo() {
- return generateInfo(true);
+ /**
+ * Returns {@code true} if the {@link SessionInfo} object should be produced with potentially
+ * sensitive data scrubbed from its fields.
+ *
+ * @param callingUid the uid of the caller; the recipient of the {@link SessionInfo} that may
+ * need to be scrubbed
+ */
+ private boolean shouldScrubData(int callingUid) {
+ return !(callingUid < Process.FIRST_APPLICATION_UID || getInstallerUid() == callingUid);
+ }
+
+ /**
+ * Generates a {@link SessionInfo} object for the provided uid. This may result in some fields
+ * that may contain sensitive info being filtered.
+ *
+ * @param includeIcon true if the icon should be included in the object
+ * @param callingUid the uid of the caller; the recipient of the {@link SessionInfo} that may
+ * need to be scrubbed
+ * @see #shouldScrubData(int)
+ */
+ public SessionInfo generateInfoForCaller(boolean includeIcon, int callingUid) {
+ return generateInfoInternal(includeIcon, shouldScrubData(callingUid));
}
- public SessionInfo generateInfo(boolean includeIcon) {
+ /**
+ * Generates a {@link SessionInfo} object to ensure proper hiding of sensitive fields.
+ *
+ * @param includeIcon true if the icon should be included in the object
+ * @see #generateInfoForCaller(boolean, int)
+ */
+ public SessionInfo generateInfoScrubbed(boolean includeIcon) {
+ return generateInfoInternal(includeIcon, true /*scrubData*/);
+ }
+
+ private SessionInfo generateInfoInternal(boolean includeIcon, boolean scrubData) {
final SessionInfo info = new SessionInfo();
synchronized (mLock) {
info.sessionId = sessionId;
@@ -484,9 +514,13 @@ public SessionInfo generateInfo(boolean includeIcon) {
info.appLabel = params.appLabel;
info.installLocation = params.installLocation;
- info.originatingUri = params.originatingUri;
+ if (!scrubData) {
+ info.originatingUri = params.originatingUri;
+ }
info.originatingUid = params.originatingUid;
- info.referrerUri = params.referrerUri;
+ if (!scrubData) {
+ info.referrerUri = params.referrerUri;
+ }
info.grantedRuntimePermissions = params.grantedRuntimePermissions;
info.whitelistedRestrictedPermissions = params.whitelistedRestrictedPermissions;
info.installFlags = params.installFlags;
@@ -2188,9 +2222,8 @@ private void dispatchSessionFinished(int returnCode, String msg, Bundle extras)
// Send broadcast to default launcher only if it's a new install
// TODO(b/144270665): Secure the usage of this broadcast.
final boolean isNewInstall = extras == null || !extras.getBoolean(Intent.EXTRA_REPLACING);
- if (success && isNewInstall && mPm.mInstallerService.okToSendBroadcasts()
- && (params.installFlags & PackageManager.INSTALL_DRY_RUN) == 0) {
- mPm.sendSessionCommitBroadcast(generateInfo(), userId);
+ if (success && isNewInstall && mPm.mInstallerService.okToSendBroadcasts()) {
+ mPm.sendSessionCommitBroadcast(generateInfoScrubbed(true /*icon*/), userId);
}
mCallback.onSessionFinished(this, success);
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 422b355f9424..52e642784dde 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -1143,13 +1143,6 @@ public void receiveVerificationResponse(int verificationId) {
int updatedStatus = INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
boolean needUpdate = false;
- if (DEBUG_DOMAIN_VERIFICATION) {
- Slog.d(TAG,
- "Updating IntentFilterVerificationInfo for package " + packageName
- + " verificationId:" + verificationId
- + " verified=" + verified);
- }
-
// In a success case, we promote from undefined or ASK to ALWAYS. This
// supports a flow where the app fails validation but then ships an updated
// APK that passes, and therefore deserves to be in ALWAYS.
@@ -11783,6 +11776,8 @@ private static void applyPolicy(PackageParser.Package pkg, final @ParseFlags int
~ApplicationInfo.PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE;
pkg.applicationInfo.privateFlags &=
~ApplicationInfo.PRIVATE_FLAG_DIRECT_BOOT_AWARE;
+ // clear protected broadcasts
+ pkg.protectedBroadcasts = null;
// cap permission priorities
if (pkg.permissionGroups != null && pkg.permissionGroups.size() > 0) {
for (int i = pkg.permissionGroups.size() - 1; i >= 0; --i) {
@@ -11791,8 +11786,6 @@ private static void applyPolicy(PackageParser.Package pkg, final @ParseFlags int
}
}
if ((scanFlags & SCAN_AS_PRIVILEGED) == 0) {
- // clear protected broadcasts
- pkg.protectedBroadcasts = null;
// ignore export request for single user receivers
if (pkg.receivers != null) {
for (int i = pkg.receivers.size() - 1; i >= 0; --i) {
@@ -14698,19 +14691,32 @@ public void setInstallerPackageName(String targetPackage, String installerPackag
// Verify: if target already has an installer package, it must
// be signed with the same cert as the caller.
- if (targetPackageSetting.installerPackageName != null) {
- PackageSetting setting = mSettings.mPackages.get(
- targetPackageSetting.installerPackageName);
- // If the currently set package isn't valid, then it's always
- // okay to change it.
- if (setting != null) {
- if (compareSignatures(callerSignature,
- setting.signatures.mSigningDetails.signatures)
- != PackageManager.SIGNATURE_MATCH) {
- throw new SecurityException(
- "Caller does not have same cert as old installer package "
- + targetPackageSetting.installerPackageName);
- }
+ String targetInstallerPackageName =
+ targetPackageSetting.installerPackageName;
+ PackageSetting targetInstallerPkgSetting = targetInstallerPackageName == null ? null :
+ mSettings.mPackages.get(targetInstallerPackageName);
+
+ if (targetInstallerPkgSetting != null) {
+ if (compareSignatures(callerSignature,
+ targetInstallerPkgSetting.signatures.mSigningDetails.signatures)
+ != PackageManager.SIGNATURE_MATCH) {
+ throw new SecurityException(
+ "Caller does not have same cert as old installer package "
+ + targetInstallerPackageName);
+ }
+ } else if (mContext.checkCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGES)
+ != PackageManager.PERMISSION_GRANTED) {
+ // This is probably an attempt to exploit vulnerability b/150857253 of taking
+ // privileged installer permissions when the installer has been uninstalled or
+ // was never set.
+ EventLog.writeEvent(0x534e4554, "150857253", callingUid, "");
+
+ if (getUidTargetSdkVersionLockedLPr(callingUid) > Build.VERSION_CODES.Q) {
+ throw new SecurityException("Neither user " + callingUid
+ + " nor current process has " + Manifest.permission.INSTALL_PACKAGES);
+ } else {
+ // If not targeting >Q, fail silently for backwards compatibility
+ return;
}
}
@@ -18280,16 +18286,18 @@ private void verifyIntentFiltersIfNeeded(int userId, int verifierUid, boolean re
int count = 0;
final String packageName = pkg.packageName;
-
boolean handlesWebUris = false;
- final boolean alreadyVerified;
+ ArraySet domains = new ArraySet<>();
+ final boolean previouslyVerified;
+ boolean hostSetExpanded = false;
+ boolean needToRunVerify = false;
synchronized (mPackages) {
// If this is a new install and we see that we've already run verification for this
// package, we have nothing to do: it means the state was restored from backup.
- final IntentFilterVerificationInfo ivi =
+ IntentFilterVerificationInfo ivi =
mSettings.getIntentFilterVerificationLPr(packageName);
- alreadyVerified = (ivi != null);
- if (!replacing && alreadyVerified) {
+ previouslyVerified = (ivi != null);
+ if (!replacing && previouslyVerified) {
if (DEBUG_DOMAIN_VERIFICATION) {
Slog.i(TAG, "Package " + packageName + " already verified: status="
+ ivi.getStatusString());
@@ -18297,77 +18305,107 @@ private void verifyIntentFiltersIfNeeded(int userId, int verifierUid, boolean re
return;
}
+ if (DEBUG_DOMAIN_VERIFICATION) {
+ Slog.i(TAG, " Previous verified hosts: "
+ + (ivi == null ? "[none]" : ivi.getDomainsString()));
+ }
+
// If any filters need to be verified, then all need to be. In addition, we need to
// know whether an updating app has any web navigation intent filters, to re-
// examine handling policy even if not re-verifying.
- boolean needToVerify = false;
+ final boolean needsVerification = needsNetworkVerificationLPr(packageName);
for (PackageParser.Activity a : pkg.activities) {
for (ActivityIntentInfo filter : a.intents) {
if (filter.handlesWebUris(true)) {
handlesWebUris = true;
}
- if (filter.needsVerification() && needsNetworkVerificationLPr(filter)) {
+ if (needsVerification && filter.needsVerification()) {
if (DEBUG_DOMAIN_VERIFICATION) {
- Slog.d(TAG,
- "Intent filter needs verification, so processing all filters");
+ Slog.d(TAG, "autoVerify requested, processing all filters");
}
- needToVerify = true;
+ needToRunVerify = true;
// It's safe to break out here because filter.needsVerification()
- // can only be true if filter.handlesWebUris(true) returns true, so
+ // can only be true if filter.handlesWebUris(true) returned true, so
// we've already noted that.
break;
}
}
}
- // Note whether this app publishes any web navigation handling support at all,
- // and whether there are any web-nav filters that fit the profile for running
- // a verification pass now.
- if (needToVerify) {
+ // Compare the new set of recognized hosts if the app is either requesting
+ // autoVerify or has previously used autoVerify but no longer does.
+ if (needToRunVerify || previouslyVerified) {
final int verificationId = mIntentFilterVerificationToken++;
for (PackageParser.Activity a : pkg.activities) {
for (ActivityIntentInfo filter : a.intents) {
// Run verification against hosts mentioned in any web-nav intent filter,
// even if the filter matches non-web schemes as well
- if (filter.handlesWebUris(false) && needsNetworkVerificationLPr(filter)) {
+ if (filter.handlesWebUris(false /*onlyWebSchemes*/)) {
if (DEBUG_DOMAIN_VERIFICATION) Slog.d(TAG,
"Verification needed for IntentFilter:" + filter.toString());
mIntentFilterVerifier.addOneIntentFilterVerification(
verifierUid, userId, verificationId, filter, packageName);
+ domains.addAll(filter.getHostsList());
count++;
}
}
}
}
+
+ if (DEBUG_DOMAIN_VERIFICATION) {
+ Slog.i(TAG, " Update published hosts: " + domains.toString());
+ }
+
+ // If we've previously verified this same host set (or a subset), we can trust that
+ // a current ALWAYS policy is still applicable. If this is the case, we're done.
+ // (If we aren't in ALWAYS, we want to reverify to allow for apps that had failing
+ // hosts in their intent filters, then pushed a new apk that removed them and now
+ // passes.)
+ //
+ // Cases:
+ // + still autoVerify (needToRunVerify):
+ // - preserve current state if all of: unexpanded, in always
+ // - otherwise rerun as usual (fall through)
+ // + no longer autoVerify (alreadyVerified && !needToRunVerify)
+ // - wipe verification history always
+ // - preserve current state if all of: unexpanded, in always
+ hostSetExpanded = !previouslyVerified
+ || (ivi != null && !ivi.getDomains().containsAll(domains));
+ final int currentPolicy =
+ mSettings.getIntentFilterVerificationStatusLPr(packageName, userId);
+ final boolean keepCurState = !hostSetExpanded
+ && currentPolicy == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS;
+
+ if (needToRunVerify && keepCurState) {
+ if (DEBUG_DOMAIN_VERIFICATION) {
+ Slog.i(TAG, "Host set not expanding + ALWAYS -> no need to reverify");
+ }
+ ivi.setDomains(domains);
+ scheduleWriteSettingsLocked();
+ return;
+ } else if (previouslyVerified && !needToRunVerify) {
+ // Prior autoVerify state but not requesting it now. Clear autoVerify history,
+ // and preserve the always policy iff the host set is not expanding.
+ clearIntentFilterVerificationsLPw(packageName, userId, !keepCurState);
+ return;
+ }
}
- if (count > 0) {
- // count > 0 means that we're running a full verification pass
+ if (needToRunVerify && count > 0) {
+ // app requested autoVerify and has at least one matching intent filter
if (DEBUG_DOMAIN_VERIFICATION) Slog.d(TAG, "Starting " + count
+ " IntentFilter verification" + (count > 1 ? "s" : "")
+ " for userId:" + userId);
mIntentFilterVerifier.startVerifications(userId);
- } else if (alreadyVerified && handlesWebUris) {
- // App used autoVerify in the past, no longer does, but still handles web
- // navigation starts.
- if (DEBUG_DOMAIN_VERIFICATION) {
- Slog.d(TAG, "App changed web filters but no longer verifying - resetting policy");
- }
- synchronized (mPackages) {
- clearIntentFilterVerificationsLPw(packageName, userId);
- }
} else {
if (DEBUG_DOMAIN_VERIFICATION) {
- Slog.d(TAG, "No web filters or no prior verify policy for " + packageName);
+ Slog.d(TAG, "No web filters or no new host policy for " + packageName);
}
}
}
@GuardedBy("mPackages")
- private boolean needsNetworkVerificationLPr(ActivityIntentInfo filter) {
- final ComponentName cn = filter.activity.getComponentName();
- final String packageName = cn.getPackageName();
-
+ private boolean needsNetworkVerificationLPr(String packageName) {
IntentFilterVerificationInfo ivi = mSettings.getIntentFilterVerificationLPr(
packageName);
if (ivi == null) {
@@ -19113,7 +19151,7 @@ private void removePackageDataLIF(final PackageSetting deletedPs, int[] allUserH
if ((flags & PackageManager.DELETE_KEEP_DATA) == 0) {
final SparseBooleanArray changedUsers = new SparseBooleanArray();
synchronized (mPackages) {
- clearIntentFilterVerificationsLPw(deletedPs.name, UserHandle.USER_ALL);
+ clearIntentFilterVerificationsLPw(deletedPs.name, UserHandle.USER_ALL, true);
clearDefaultBrowserIfNeeded(packageName);
mSettings.mKeySetManagerService.removeAppKeySetDataLPw(packageName);
removedAppId = mSettings.removePackageLPw(packageName);
@@ -20618,13 +20656,14 @@ private void clearIntentFilterVerificationsLPw(int userId) {
final int packageCount = mPackages.size();
for (int i = 0; i < packageCount; i++) {
PackageParser.Package pkg = mPackages.valueAt(i);
- clearIntentFilterVerificationsLPw(pkg.packageName, userId);
+ clearIntentFilterVerificationsLPw(pkg.packageName, userId, true);
}
}
/** This method takes a specific user id as well as UserHandle.USER_ALL. */
@GuardedBy("mPackages")
- void clearIntentFilterVerificationsLPw(String packageName, int userId) {
+ void clearIntentFilterVerificationsLPw(String packageName, int userId,
+ boolean alsoResetStatus) {
if (userId == UserHandle.USER_ALL) {
if (mSettings.removeIntentFilterVerificationLPw(packageName,
sUserManager.getUserIds())) {
@@ -20633,7 +20672,8 @@ void clearIntentFilterVerificationsLPw(String packageName, int userId) {
}
}
} else {
- if (mSettings.removeIntentFilterVerificationLPw(packageName, userId)) {
+ if (mSettings.removeIntentFilterVerificationLPw(packageName, userId,
+ alsoResetStatus)) {
scheduleWritePackageRestrictionsLocked(userId);
}
}
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 062e28a73a18..a3dbfdc099d2 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -1243,7 +1243,8 @@ List getIntentFilterVerificationsLPr(
return result;
}
- boolean removeIntentFilterVerificationLPw(String packageName, int userId) {
+ boolean removeIntentFilterVerificationLPw(String packageName, int userId,
+ boolean alsoResetStatus) {
PackageSetting ps = mPackages.get(packageName);
if (ps == null) {
if (DEBUG_DOMAIN_VERIFICATION) {
@@ -1251,7 +1252,9 @@ boolean removeIntentFilterVerificationLPw(String packageName, int userId) {
}
return false;
}
- ps.clearDomainVerificationStatusForUser(userId);
+ if (alsoResetStatus) {
+ ps.clearDomainVerificationStatusForUser(userId);
+ }
ps.setIntentFilterVerificationInfo(null);
return true;
}
@@ -1259,7 +1262,7 @@ boolean removeIntentFilterVerificationLPw(String packageName, int userId) {
boolean removeIntentFilterVerificationLPw(String packageName, int[] userIds) {
boolean result = false;
for (int userId : userIds) {
- result |= removeIntentFilterVerificationLPw(packageName, userId);
+ result |= removeIntentFilterVerificationLPw(packageName, userId, true);
}
return result;
}
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index 895d2c5d00bf..dd7133121b21 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -95,11 +95,12 @@ private void updateStoredSession(@NonNull PackageInstallerSession sessionInfo) {
}
}
- ParceledListSlice getSessions() {
+ ParceledListSlice getSessions(int callingUid) {
final List result = new ArrayList<>();
synchronized (mStagedSessions) {
for (int i = 0; i < mStagedSessions.size(); i++) {
- result.add(mStagedSessions.valueAt(i).generateInfo(false));
+ final PackageInstallerSession stagedSession = mStagedSessions.valueAt(i);
+ result.add(stagedSession.generateInfoForCaller(false /*icon*/, callingUid));
}
}
return new ParceledListSlice<>(result);
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 0e2f0ce991c7..0ec366c91528 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -715,6 +715,7 @@ private void generateCrop(WallpaperData wallpaper) {
estimateCrop.bottom = estimateCrop.top + newHeight;
cropHint.set(estimateCrop);
estimateCrop.scale(1f / options.inSampleSize);
+
}
// We've got the safe cropHint; now we want to scale it properly to