Merge changes from topic 'f-radio-toggle' into cw-f-dev
* changes:
Add WiFi toggle prompts - framework
Add Bluetooth toggle prompts - framework
diff --git a/cmds/svc/src/com/android/commands/svc/WifiCommand.java b/cmds/svc/src/com/android/commands/svc/WifiCommand.java
index 94214ff..633dd97 100644
--- a/cmds/svc/src/com/android/commands/svc/WifiCommand.java
+++ b/cmds/svc/src/com/android/commands/svc/WifiCommand.java
@@ -52,7 +52,7 @@
IWifiManager wifiMgr
= IWifiManager.Stub.asInterface(ServiceManager.getService(Context.WIFI_SERVICE));
try {
- wifiMgr.setWifiEnabled(flag);
+ wifiMgr.setWifiEnabled("com.android.shell", flag);
}
catch (RemoteException e) {
System.err.println("Wi-Fi operation failed: " + e);
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index 4f19dca..542b06b 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -23,6 +23,7 @@
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 @@
"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>
*
@@ -772,7 +796,7 @@
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);
}
@@ -899,7 +923,7 @@
return true;
}
try {
- return mManagerService.enable();
+ return mManagerService.enable(ActivityThread.currentPackageName());
} catch (RemoteException e) {Log.e(TAG, "", e);}
return false;
}
@@ -931,7 +955,7 @@
@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;
}
@@ -949,7 +973,7 @@
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 2b853a3..90f0085 100644
--- a/core/java/android/bluetooth/IBluetoothManager.aidl
+++ b/core/java/android/bluetooth/IBluetoothManager.aidl
@@ -34,9 +34,9 @@
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/config.xml b/core/res/res/values/config.xml
index 90c19fb..6a46954 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2675,4 +2675,12 @@
<!-- An array of packages for which notifications cannot be blocked. -->
<string-array translatable="false" name="config_nonBlockableNotificationPackages" />
+
+ <!-- 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 bbfee14..17c88b9 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2730,4 +2730,7 @@
<!-- Screen-size-dependent modes for picker dialogs. -->
<java-symbol type="integer" name="time_picker_mode" />
<java-symbol type="integer" name="date_picker_mode" />
+
+ <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 52be811..a3af5c64 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.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 @@
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,
@@ -244,6 +248,11 @@
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;
@@ -654,15 +663,26 @@
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);
@@ -678,14 +698,24 @@
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) {
@@ -706,6 +736,31 @@
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 1bcff1a..3f6a83f 100755
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -368,7 +368,7 @@
// 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;
@@ -912,7 +912,7 @@
// 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 7c9497d..d2babe3 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -1576,6 +1576,8 @@
// 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;
@@ -2623,6 +2625,9 @@
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();
@@ -10863,7 +10868,7 @@
// 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 d5b29c6..c234ac5 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 @@
// 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 7873b7a..8f2e05f7 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 @@
// 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 @@
// 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 e5da1fb..3bd533d 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 @@
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 @@
}
mContext = context;
+
+ mPermissionReviewRequired = context.getResources().getBoolean(
+ R.bool.config_permissionReviewRequired);
+
mFactoryTest = factoryTest;
mOnlyCore = onlyCore;
mMetrics = new DisplayMetrics();
@@ -4050,7 +4056,7 @@
// 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;
@@ -4161,7 +4167,7 @@
// 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;
@@ -10022,7 +10028,8 @@
// 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)) {
@@ -10108,7 +10115,7 @@
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) {
@@ -10117,7 +10124,8 @@
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.
@@ -16712,7 +16720,7 @@
// 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;
}
@@ -20587,7 +20595,7 @@
// 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);
}
@@ -21041,7 +21049,7 @@
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 44894ed..badee82 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 @@
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);
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index 9268a2b..6c95865 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -89,7 +89,7 @@
WifiInfo getConnectionInfo();
- boolean setWifiEnabled(boolean enable);
+ boolean setWifiEnabled(String packageName, boolean enable);
int getWifiEnabledState();
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 1633bd9c9..7fa2c47 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -19,6 +19,7 @@
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.SystemApi;
+import android.bluetooth.BluetoothAdapter;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.DhcpInfo;
@@ -563,6 +564,28 @@
public static final String ACTION_PICK_WIFI_NETWORK = "android.net.wifi.PICK_WIFI_NETWORK";
/**
+ * Activity Action: Show UI to get user approval to enable WiFi.
+ * <p>Input: {@link android.content.Intent#EXTRA_PACKAGE_NAME} string extra with
+ * the name of the app requesting the action.
+ * <p>Output: Nothing.
+ *
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_REQUEST_ENABLE = "android.net.wifi.action.REQUEST_ENABLE";
+
+ /**
+ * Activity Action: Show UI to get user approval to disable WiFi.
+ * <p>Input: {@link android.content.Intent#EXTRA_PACKAGE_NAME} string extra with
+ * the name of the app requesting the action.
+ * <p>Output: Nothing.
+ *
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_REQUEST_DISABLE = "android.net.wifi.action.REQUEST_DISABLE";
+
+ /**
* Internally used Wi-Fi lock mode representing the case were no locks are held.
* @hide
*/
@@ -1445,7 +1468,7 @@
*/
public boolean setWifiEnabled(boolean enabled) {
try {
- return mService.setWifiEnabled(enabled);
+ return mService.setWifiEnabled(mContext.getOpPackageName(), enabled);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}