summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/bluetooth/BluetoothAdapter.java32
-rw-r--r--core/java/android/bluetooth/IBluetoothManager.aidl5
-rw-r--r--core/res/res/values/config.xml7
-rw-r--r--core/res/res/values/symbols.xml3
-rw-r--r--services/core/java/com/android/server/BluetoothManagerService.java83
-rw-r--r--services/core/java/com/android/server/am/ActiveServices.java4
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java7
-rw-r--r--services/core/java/com/android/server/am/ActivityStarter.java3
-rw-r--r--services/core/java/com/android/server/am/BroadcastQueue.java5
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java24
-rw-r--r--services/core/java/com/android/server/power/ShutdownThread.java2
11 files changed, 140 insertions, 35 deletions
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index cd1a3dd02b61..073196cf7c0c 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;
@@ -252,6 +253,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>
*
@@ -775,7 +799,7 @@ public final class BluetoothAdapter {
try {
if (DBG) Log.d(TAG, "Calling enableBLE");
mManagerService.updateBleAppCount(mToken, true);
- return mManagerService.enable();
+ return mManagerService.enable(ActivityThread.currentPackageName());
} catch (RemoteException e) {
Log.e(TAG, "", e);
}
@@ -902,7 +926,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;
}
@@ -934,7 +958,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;
}
@@ -952,7 +976,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 0b81ee8c547e..f39ca8e0e9c8 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);
IBluetoothGatt getBluetoothGatt();
boolean bindBluetoothProfileService(int profile, IBluetoothProfileServiceConnection proxy);
@@ -49,3 +49,4 @@ interface IBluetoothManager
int updateBleAppCount(IBinder b, boolean enable);
boolean isBleAppPresent();
}
+
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 2b39f1876ee3..0201111e4a22 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2502,4 +2502,11 @@
<item>405</item>
</integer-array>
+ <!-- Specifies whether the permissions needed by a legacy app should be
+ reviewed before any of its components can run. A legacy app is one
+ with targetSdkVersion < 23, i.e apps using the old permission model.
+ If review is not required, permissions are reviewed before the app
+ is installed. -->
+ <bool name="config_permissionReviewRequired">false</bool>
+
</resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 23cd7e6fb616..23458851acc1 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2616,4 +2616,7 @@
<java-symbol type="array" name="config_emergency_mcc_codes" />
<java-symbol type="drawable" name="emergency_icon" />
+
+ <java-symbol type="bool" name="config_permissionReviewRequired" />
+
</resources>
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index 6575a2a86cb9..7875cb86ee78 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -35,10 +35,12 @@ 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.Build;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
@@ -151,6 +153,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,
@@ -243,6 +247,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;
@@ -626,15 +635,26 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
return true;
}
- public boolean enable() {
- if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
- (!checkIfCallerIsForegroundUser())) {
- Slog.w(TAG,"enable(): not allowed for non-active and non system user");
- return false;
+ public boolean enable(String packageName) throws RemoteException {
+ 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);
@@ -650,14 +670,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) {
@@ -678,6 +708,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 d9148817881b..2d534171b94d 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -368,7 +368,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;
@@ -891,7 +891,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 fdde15013663..b59f4686998e 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -1558,6 +1558,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;
@@ -2584,6 +2586,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();
@@ -10741,7 +10746,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 32a798b33bcf..5bd6bed75281 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -410,7 +410,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 8e33c4f4bc35..2e1958cc7ba8 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -618,7 +618,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;
@@ -1124,7 +1124,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 85cc12427cef..70560c72bc61 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -1119,6 +1119,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();
@@ -2053,6 +2055,10 @@ public class PackageManagerService extends IPackageManager.Stub {
}
mContext = context;
+
+ mPermissionReviewRequired = context.getResources().getBoolean(
+ R.bool.config_permissionReviewRequired);
+
mFactoryTest = factoryTest;
mOnlyCore = onlyCore;
mMetrics = new DisplayMetrics();
@@ -3965,7 +3971,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;
@@ -4076,7 +4082,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;
@@ -9866,7 +9872,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)) {
@@ -9952,7 +9959,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) {
@@ -9961,7 +9968,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.
@@ -16423,7 +16431,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;
}
@@ -20272,7 +20280,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);
}
@@ -20726,7 +20734,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 f7f79f324ecc..02dd53dc5243 100644
--- a/services/core/java/com/android/server/power/ShutdownThread.java
+++ b/services/core/java/com/android/server/power/ShutdownThread.java
@@ -546,7 +546,7 @@ public final class ShutdownThread extends Thread {
bluetoothOff = bluetooth == null || !bluetooth.isEnabled();
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);