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