diff options
| author | 2016-12-12 21:27:23 +0000 | |
|---|---|---|
| committer | 2016-12-12 21:27:23 +0000 | |
| commit | 47e1f497c0f457fd010e35d7aba1c9987fd9ea0f (patch) | |
| tree | 1653471f4a437bda6a841b5213382852ba244923 | |
| parent | 9b430e0395444aba316bc2226bb71a8e25274027 (diff) | |
| parent | c2ac5bde6f6e9cc95a476a2404f020246516ccfc (diff) | |
Merge "DO NOT MERGE Add Bluetooth toggle prompts - framework"
10 files changed, 135 insertions, 38 deletions
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java index d419d0384f5c..61544e4f927a 100644 --- a/core/java/android/bluetooth/BluetoothAdapter.java +++ b/core/java/android/bluetooth/BluetoothAdapter.java @@ -23,6 +23,7 @@ import android.annotation.RequiresPermission; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SystemApi; +import android.app.ActivityThread; import android.bluetooth.le.BluetoothLeAdvertiser; import android.bluetooth.le.BluetoothLeScanner; import android.bluetooth.le.ScanCallback; @@ -255,6 +256,29 @@ public final class BluetoothAdapter { "android.bluetooth.adapter.action.REQUEST_ENABLE"; /** + * Activity Action: Show a system activity that allows the user to turn off + * Bluetooth. This is used only if permission review is enabled which is for + * apps targeting API less than 23 require a permission review before any of + * the app's components can run. + * <p>This system activity will return once Bluetooth has completed turning + * off, or the user has decided not to turn Bluetooth off. + * <p>Notification of the result of this activity is posted using the + * {@link android.app.Activity#onActivityResult} callback. The + * <code>resultCode</code> + * will be {@link android.app.Activity#RESULT_OK} if Bluetooth has been + * turned off or {@link android.app.Activity#RESULT_CANCELED} if the user + * has rejected the request or an error has occurred. + * <p>Applications can also listen for {@link #ACTION_STATE_CHANGED} + * for global notification whenever Bluetooth is turned on or off. + * <p>Requires {@link android.Manifest.permission#BLUETOOTH} + * + * @hide + */ + @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) + public static final String ACTION_REQUEST_DISABLE = + "android.bluetooth.adapter.action.REQUEST_DISABLE"; + + /** * Activity Action: Show a system activity that allows user to enable BLE scans even when * Bluetooth is turned off.<p> * @@ -768,7 +792,7 @@ public final class BluetoothAdapter { return true; } if (DBG) Log.d(TAG, "enableBLE(): Calling enable"); - return mManagerService.enable(); + return mManagerService.enable(ActivityThread.currentPackageName()); } catch (RemoteException e) { Log.e(TAG, "", e); } @@ -895,7 +919,7 @@ public final class BluetoothAdapter { return true; } try { - return mManagerService.enable(); + return mManagerService.enable(ActivityThread.currentPackageName()); } catch (RemoteException e) {Log.e(TAG, "", e);} return false; } @@ -927,7 +951,7 @@ public final class BluetoothAdapter { @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) public boolean disable() { try { - return mManagerService.disable(true); + return mManagerService.disable(ActivityThread.currentPackageName(), true); } catch (RemoteException e) {Log.e(TAG, "", e);} return false; } @@ -945,7 +969,7 @@ public final class BluetoothAdapter { public boolean disable(boolean persist) { try { - return mManagerService.disable(persist); + return mManagerService.disable(ActivityThread.currentPackageName(), persist); } catch (RemoteException e) {Log.e(TAG, "", e);} return false; } diff --git a/core/java/android/bluetooth/IBluetoothManager.aidl b/core/java/android/bluetooth/IBluetoothManager.aidl index 2b853a373b52..2ab9ae80b442 100644 --- a/core/java/android/bluetooth/IBluetoothManager.aidl +++ b/core/java/android/bluetooth/IBluetoothManager.aidl @@ -34,9 +34,9 @@ interface IBluetoothManager void registerStateChangeCallback(in IBluetoothStateChangeCallback callback); void unregisterStateChangeCallback(in IBluetoothStateChangeCallback callback); boolean isEnabled(); - boolean enable(); + boolean enable(String packageName); boolean enableNoAutoConnect(); - boolean disable(boolean persist); + boolean disable( String packageName, boolean persist); int getState(); IBluetoothGatt getBluetoothGatt(); diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index c26fac1c3c74..ddf8f25248a6 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -2716,7 +2716,6 @@ <java-symbol type="bool" name="config_permissionReviewRequired" /> - <java-symbol type="drawable" name="ic_restart" /> <java-symbol type="drawable" name="emergency_icon" /> @@ -2731,5 +2730,4 @@ <!-- Network Recommendation --> <java-symbol type="array" name="config_networkRecommendationPackageNames" /> - </resources> diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java index 75b2dd494b68..5cf9eead5de7 100644 --- a/services/core/java/com/android/server/BluetoothManagerService.java +++ b/services/core/java/com/android/server/BluetoothManagerService.java @@ -35,11 +35,13 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.ServiceConnection; +import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.UserInfo; import android.database.ContentObserver; import android.os.Binder; import android.os.Bundle; +import android.os.Build; import android.os.Handler; import android.os.IBinder; import android.os.Looper; @@ -154,6 +156,8 @@ class BluetoothManagerService extends IBluetoothManager.Stub { private final Map <Integer, ProfileServiceConnections> mProfileServices = new HashMap <Integer, ProfileServiceConnections>(); + private final boolean mPermissionReviewRequired; + private void registerForAirplaneMode(IntentFilter filter) { final ContentResolver resolver = mContext.getContentResolver(); final String airplaneModeRadios = Settings.Global.getString(resolver, @@ -183,7 +187,12 @@ class BluetoothManagerService extends IBluetoothManager.Stub { final boolean bluetoothDisallowed = newRestrictions.getBoolean(UserManager.DISALLOW_BLUETOOTH); if ((mEnable || mEnableExternal) && bluetoothDisallowed) { - disable(true); + try { + disable("android.os.UserManagerInternal", true); + } catch (RemoteException e) { + // Shouldn't happen: startConsentUiIfNeeded not called + // when from system. + } } } }; @@ -257,6 +266,11 @@ class BluetoothManagerService extends IBluetoothManager.Stub { mHandler = new BluetoothHandler(IoThread.get().getLooper()); mContext = context; + + mPermissionReviewRequired = Build.PERMISSIONS_REVIEW_REQUIRED + || context.getResources().getBoolean( + com.android.internal.R.bool.config_permissionReviewRequired); + mBluetooth = null; mBluetoothBinder = null; mBluetoothGatt = null; @@ -665,7 +679,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub { return true; } - public boolean enable() { + public boolean enable(String packageName) throws RemoteException { if (isBluetoothDisallowed()) { if (DBG) { Slog.d(TAG,"enable(): not enabling - bluetooth disallowed"); @@ -673,14 +687,25 @@ class BluetoothManagerService extends IBluetoothManager.Stub { return false; } - if ((Binder.getCallingUid() != Process.SYSTEM_UID) && - (!checkIfCallerIsForegroundUser())) { - Slog.w(TAG,"enable(): not allowed for non-active and non system user"); - return false; + final int callingUid = Binder.getCallingUid(); + final boolean callerSystem = UserHandle.getAppId(callingUid) == Process.SYSTEM_UID; + + if (!callerSystem) { + if (!checkIfCallerIsForegroundUser()) { + Slog.w(TAG, "enable(): not allowed for non-active and non system user"); + return false; + } + + mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, + "Need BLUETOOTH ADMIN permission"); + + if (!isEnabled() && mPermissionReviewRequired + && startConsentUiIfNeeded(packageName, callingUid, + BluetoothAdapter.ACTION_REQUEST_ENABLE)) { + return false; + } } - mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, - "Need BLUETOOTH ADMIN permission"); if (DBG) { Slog.d(TAG,"enable(): mBluetooth =" + mBluetooth + " mBinding = " + mBinding + " mState = " + mState); @@ -696,14 +721,24 @@ class BluetoothManagerService extends IBluetoothManager.Stub { return true; } - public boolean disable(boolean persist) { - mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, - "Need BLUETOOTH ADMIN permissicacheNameAndAddresson"); + public boolean disable(String packageName, boolean persist) throws RemoteException { + final int callingUid = Binder.getCallingUid(); + final boolean callerSystem = UserHandle.getAppId(callingUid) == Process.SYSTEM_UID; - if ((Binder.getCallingUid() != Process.SYSTEM_UID) && - (!checkIfCallerIsForegroundUser())) { - Slog.w(TAG,"disable(): not allowed for non-active and non system user"); - return false; + if (!callerSystem) { + if (!checkIfCallerIsForegroundUser()) { + Slog.w(TAG, "disable(): not allowed for non-active and non system user"); + return false; + } + + mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, + "Need BLUETOOTH ADMIN permission"); + + if (isEnabled() && mPermissionReviewRequired + && startConsentUiIfNeeded(packageName, callingUid, + BluetoothAdapter.ACTION_REQUEST_DISABLE)) { + return false; + } } if (DBG) { @@ -724,6 +759,31 @@ class BluetoothManagerService extends IBluetoothManager.Stub { return true; } + private boolean startConsentUiIfNeeded(String packageName, + int callingUid, String intentAction) throws RemoteException { + try { + // Validate the package only if we are going to use it + ApplicationInfo applicationInfo = mContext.getPackageManager() + .getApplicationInfoAsUser(packageName, + PackageManager.MATCH_DEBUG_TRIAGED_MISSING, + UserHandle.getUserId(callingUid)); + if (applicationInfo.uid != callingUid) { + throw new SecurityException("Package " + callingUid + + " not in uid " + callingUid); + } + + // Legacy apps in permission review mode trigger a user prompt + if (applicationInfo.targetSdkVersion < Build.VERSION_CODES.M) { + Intent intent = new Intent(intentAction); + mContext.startActivity(intent); + return true; + } + } catch (PackageManager.NameNotFoundException e) { + throw new RemoteException(e.getMessage()); + } + return false; + } + public void unbindAndFinish() { if (DBG) { Slog.d(TAG,"unbindAndFinish(): " + mBluetooth + diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index 10a538863c25..ae1aef650ba4 100644 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -369,7 +369,7 @@ public final class ActiveServices { // we do not start the service and launch a review activity if the calling app // is in the foreground passing it a pending intent to start the service when // review is completed. - if (Build.PERMISSIONS_REVIEW_REQUIRED) { + if (mAm.mPermissionReviewRequired || Build.PERMISSIONS_REVIEW_REQUIRED) { if (!requestStartTargetPermissionsReviewIfNeededLocked(r, callingPackage, callingUid, service, callerFg, userId)) { return null; @@ -913,7 +913,7 @@ public final class ActiveServices { // we schedule binding to the service but do not start its process, then // we launch a review activity to which is passed a callback to invoke // when done to start the bound service's process to completing the binding. - if (Build.PERMISSIONS_REVIEW_REQUIRED) { + if (mAm.mPermissionReviewRequired || Build.PERMISSIONS_REVIEW_REQUIRED) { if (mAm.getPackageManagerInternalLocked().isPermissionsReviewRequired( s.packageName, s.userId)) { diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index f6ce503fa586..fa54a6117ae3 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -1575,6 +1575,8 @@ public final class ActivityManagerService extends ActivityManagerNative // being called for multiwindow assist in a single session. private int mViSessionId = 1000; + final boolean mPermissionReviewRequired; + final class KillHandler extends Handler { static final int KILL_PROCESS_GROUP_MSG = 4000; @@ -2622,6 +2624,9 @@ public final class ActivityManagerService extends ActivityManagerNative Slog.i(TAG, "Memory class: " + ActivityManager.staticGetMemoryClass()); + mPermissionReviewRequired = mContext.getResources().getBoolean( + com.android.internal.R.bool.config_permissionReviewRequired); + mHandlerThread = new ServiceThread(TAG, android.os.Process.THREAD_PRIORITY_FOREGROUND, false /*allowIo*/); mHandlerThread.start(); @@ -10824,7 +10829,7 @@ public final class ActivityManagerService extends ActivityManagerNative // If permissions need a review before any of the app components can run, // we return no provider and launch a review activity if the calling app // is in the foreground. - if (Build.PERMISSIONS_REVIEW_REQUIRED) { + if (mPermissionReviewRequired || Build.PERMISSIONS_REVIEW_REQUIRED) { if (!requestTargetProviderPermissionsReviewIfNeededLocked(cpi, r, userId)) { return null; } diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java index 115971f6fffc..907394e39b14 100644 --- a/services/core/java/com/android/server/am/ActivityStarter.java +++ b/services/core/java/com/android/server/am/ActivityStarter.java @@ -416,7 +416,8 @@ class ActivityStarter { // If permissions need a review before any of the app components can run, we // launch the review activity and pass a pending intent to start the activity // we are to launching now after the review is completed. - if (Build.PERMISSIONS_REVIEW_REQUIRED && aInfo != null) { + if ((mService.mPermissionReviewRequired + || Build.PERMISSIONS_REVIEW_REQUIRED) && aInfo != null) { if (mService.getPackageManagerInternalLocked().isPermissionsReviewRequired( aInfo.packageName, userId)) { IIntentSender target = mService.getIntentSenderLocked( diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java index 362a3479a6bf..ea901ce28953 100644 --- a/services/core/java/com/android/server/am/BroadcastQueue.java +++ b/services/core/java/com/android/server/am/BroadcastQueue.java @@ -626,7 +626,7 @@ public final class BroadcastQueue { // the broadcast and if the calling app is in the foreground and the broadcast is // explicit we launch the review UI passing it a pending intent to send the skipped // broadcast. - if (Build.PERMISSIONS_REVIEW_REQUIRED) { + if (mService.mPermissionReviewRequired || Build.PERMISSIONS_REVIEW_REQUIRED) { if (!requestStartTargetPermissionsReviewIfNeededLocked(r, filter.packageName, filter.owningUserId)) { r.delivery[index] = BroadcastRecord.DELIVERY_SKIPPED; @@ -1132,7 +1132,8 @@ public final class BroadcastQueue { // the broadcast and if the calling app is in the foreground and the broadcast is // explicit we launch the review UI passing it a pending intent to send the skipped // broadcast. - if (Build.PERMISSIONS_REVIEW_REQUIRED && !skip) { + if ((mService.mPermissionReviewRequired + || Build.PERMISSIONS_REVIEW_REQUIRED) && !skip) { if (!requestStartTargetPermissionsReviewIfNeededLocked(r, info.activityInfo.packageName, UserHandle.getUserId( info.activityInfo.applicationInfo.uid))) { diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 87eafd7e16eb..fb06f0178dc4 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -1140,6 +1140,8 @@ public class PackageManagerService extends IPackageManager.Stub { final @NonNull String mServicesSystemSharedLibraryPackageName; final @NonNull String mSharedSystemSharedLibraryPackageName; + final boolean mPermissionReviewRequired; + private final PackageUsage mPackageUsage = new PackageUsage(); private final CompilerStats mCompilerStats = new CompilerStats(); @@ -2070,6 +2072,10 @@ public class PackageManagerService extends IPackageManager.Stub { } mContext = context; + + mPermissionReviewRequired = context.getResources().getBoolean( + R.bool.config_permissionReviewRequired); + mFactoryTest = factoryTest; mOnlyCore = onlyCore; mMetrics = new DisplayMetrics(); @@ -4027,7 +4033,7 @@ public class PackageManagerService extends IPackageManager.Stub { // their permissions as always granted runtime ones since we need // to keep the review required permission flag per user while an // install permission's state is shared across all users. - if (Build.PERMISSIONS_REVIEW_REQUIRED + if ((mPermissionReviewRequired || Build.PERMISSIONS_REVIEW_REQUIRED) && pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M && bp.isRuntime()) { return; @@ -4138,7 +4144,7 @@ public class PackageManagerService extends IPackageManager.Stub { // their permissions as always granted runtime ones since we need // to keep the review required permission flag per user while an // install permission's state is shared across all users. - if (Build.PERMISSIONS_REVIEW_REQUIRED + if ((mPermissionReviewRequired || Build.PERMISSIONS_REVIEW_REQUIRED) && pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M && bp.isRuntime()) { return; @@ -10019,7 +10025,8 @@ public class PackageManagerService extends IPackageManager.Stub { // their permissions as always granted runtime ones since we need // to keep the review required permission flag per user while an // install permission's state is shared across all users. - if (!appSupportsRuntimePermissions && !Build.PERMISSIONS_REVIEW_REQUIRED) { + if (!appSupportsRuntimePermissions && !mPermissionReviewRequired + && !Build.PERMISSIONS_REVIEW_REQUIRED) { // For legacy apps dangerous permissions are install time ones. grant = GRANT_INSTALL; } else if (origPermissions.hasInstallPermission(bp.name)) { @@ -10105,7 +10112,7 @@ public class PackageManagerService extends IPackageManager.Stub { changedRuntimePermissionUserIds, userId); } // If the app supports runtime permissions no need for a review. - if (Build.PERMISSIONS_REVIEW_REQUIRED + if ((mPermissionReviewRequired || Build.PERMISSIONS_REVIEW_REQUIRED) && appSupportsRuntimePermissions && (flags & PackageManager .FLAG_PERMISSION_REVIEW_REQUIRED) != 0) { @@ -10114,7 +10121,8 @@ public class PackageManagerService extends IPackageManager.Stub { changedRuntimePermissionUserIds = ArrayUtils.appendInt( changedRuntimePermissionUserIds, userId); } - } else if (Build.PERMISSIONS_REVIEW_REQUIRED + } else if ((mPermissionReviewRequired + || Build.PERMISSIONS_REVIEW_REQUIRED) && !appSupportsRuntimePermissions) { // For legacy apps that need a permission review, every new // runtime permission is granted but it is pending a review. @@ -16709,7 +16717,7 @@ public class PackageManagerService extends IPackageManager.Stub { // If permission review is enabled and this is a legacy app, mark the // permission as requiring a review as this is the initial state. int flags = 0; - if (Build.PERMISSIONS_REVIEW_REQUIRED + if ((mPermissionReviewRequired || Build.PERMISSIONS_REVIEW_REQUIRED) && ps.pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M) { flags |= FLAG_PERMISSION_REVIEW_REQUIRED; } @@ -20578,7 +20586,7 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); // permissions to keep per user flag state whether review is needed. // Hence, if a new user is added we have to propagate dangerous // permission grants for these legacy apps. - if (Build.PERMISSIONS_REVIEW_REQUIRED) { + if (mPermissionReviewRequired || Build.PERMISSIONS_REVIEW_REQUIRED) { updatePermissionsLPw(null, null, UPDATE_PERMISSIONS_ALL | UPDATE_PERMISSIONS_REPLACE_ALL); } @@ -21032,7 +21040,7 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); public boolean isPermissionsReviewRequired(String packageName, int userId) { synchronized (mPackages) { // If we do not support permission review, done. - if (!Build.PERMISSIONS_REVIEW_REQUIRED) { + if (!mPermissionReviewRequired && !Build.PERMISSIONS_REVIEW_REQUIRED) { return false; } diff --git a/services/core/java/com/android/server/power/ShutdownThread.java b/services/core/java/com/android/server/power/ShutdownThread.java index 44894ed99bb2..badee82becbd 100644 --- a/services/core/java/com/android/server/power/ShutdownThread.java +++ b/services/core/java/com/android/server/power/ShutdownThread.java @@ -547,7 +547,7 @@ public final class ShutdownThread extends Thread { bluetooth.getState() == BluetoothAdapter.STATE_OFF; if (!bluetoothOff) { Log.w(TAG, "Disabling Bluetooth..."); - bluetooth.disable(false); // disable but don't persist new state + bluetooth.disable(mContext.getPackageName(), false); // disable but don't persist new state } } catch (RemoteException ex) { Log.e(TAG, "RemoteException during bluetooth shutdown", ex); |