Mark framework created intent as safe
Flag intent created by framework as LOCAL_FLAG_FROM_PROTECTED_COMPONENT by
calling intent.prepareToEnterProcess(true...). This is to fix false positives
of StrictMode.unsafeIntentLaunchViolation.
Bug: 181132616
Test: Manually verified a violation was not reported when a test app launched
Intents returned from TelecomManager.createManageBlockedNumbersIntent.
Methods marked as systemApi are not tested.
Change-Id: I7b00008dd894f1c637ab2f0a23e6cafb58bb73e5
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 6866510..c12e26b 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -16,6 +16,7 @@
package android.app.admin;
+import static android.content.Intent.LOCAL_FLAG_FROM_SYSTEM;
import static android.net.NetworkCapabilities.NET_ENTERPRISE_ID_1;
import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
@@ -10802,14 +10803,19 @@
*/
public Intent createAdminSupportIntent(@NonNull String restriction) {
throwIfParentInstance("createAdminSupportIntent");
+ Intent result = null;
if (mService != null) {
try {
- return mService.createAdminSupportIntent(restriction);
+ result = mService.createAdminSupportIntent(restriction);
+ if (result != null) {
+ result.prepareToEnterProcess(LOCAL_FLAG_FROM_SYSTEM,
+ mContext.getAttributionSource());
+ }
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
- return null;
+ return result;
}
/**
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 0e0b2dc..48f715c 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -7124,12 +7124,18 @@
*/
private static final int LOCAL_FLAG_FROM_URI = 1 << 4;
+ /**
+ * Local flag indicating this instance was created by the system.
+ */
+ /** @hide */
+ public static final int LOCAL_FLAG_FROM_SYSTEM = 1 << 5;
+
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
// toUri() and parseUri() options.
/** @hide */
- @IntDef(flag = true, prefix = { "URI_" }, value = {
+ @IntDef(flag = true, prefix = {"URI_"}, value = {
URI_ALLOW_UNSAFE,
URI_ANDROID_APP_SCHEME,
URI_INTENT_SCHEME,
@@ -10535,7 +10541,9 @@
// delivered Intent then it would have been reported when that Intent left the sending
// process.
if ((src.mLocalFlags & LOCAL_FLAG_FROM_PARCEL) != 0
- && (src.mLocalFlags & LOCAL_FLAG_FROM_PROTECTED_COMPONENT) == 0) {
+ && (src.mLocalFlags & (
+ LOCAL_FLAG_FROM_PROTECTED_COMPONENT
+ | LOCAL_FLAG_FROM_SYSTEM)) == 0) {
mLocalFlags |= LOCAL_FLAG_UNFILTERED_EXTRAS;
}
return this;
@@ -11878,13 +11886,14 @@
// Detect cases where we're about to launch a potentially unsafe intent
if (StrictMode.vmUnsafeIntentLaunchEnabled()) {
if ((mLocalFlags & LOCAL_FLAG_FROM_PARCEL) != 0
- && (mLocalFlags & LOCAL_FLAG_FROM_PROTECTED_COMPONENT) == 0) {
+ && (mLocalFlags
+ & (LOCAL_FLAG_FROM_PROTECTED_COMPONENT | LOCAL_FLAG_FROM_SYSTEM)) == 0) {
StrictMode.onUnsafeIntentLaunch(this);
} else if ((mLocalFlags & LOCAL_FLAG_UNFILTERED_EXTRAS) != 0) {
StrictMode.onUnsafeIntentLaunch(this);
} else if ((mLocalFlags & LOCAL_FLAG_FROM_URI) != 0
&& !(mCategories != null && mCategories.contains(CATEGORY_BROWSABLE)
- && mComponent == null)) {
+ && mComponent == null)) {
// Since the docs for #URI_ALLOW_UNSAFE recommend setting the category to browsable
// for an implicit Intent parsed from a URI a violation should be reported if these
// conditions are not met.
@@ -11897,6 +11906,17 @@
* @hide
*/
public void prepareToEnterProcess(boolean fromProtectedComponent, AttributionSource source) {
+ if (fromProtectedComponent) {
+ prepareToEnterProcess(LOCAL_FLAG_FROM_PROTECTED_COMPONENT, source);
+ } else {
+ prepareToEnterProcess(0, source);
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public void prepareToEnterProcess(int localFlags, AttributionSource source) {
// We just entered destination process, so we should be able to read all
// parcelables inside.
setDefusable(true);
@@ -11904,13 +11924,15 @@
if (mSelector != null) {
// We can't recursively claim that this data is from a protected
// component, since it may have been filled in by a malicious app
- mSelector.prepareToEnterProcess(false, source);
+ mSelector.prepareToEnterProcess(0, source);
}
if (mClipData != null) {
mClipData.prepareToEnterProcess(source);
}
if (mOriginalIntent != null) {
- mOriginalIntent.prepareToEnterProcess(false, source);
+ // We can't recursively claim that this data is from a protected
+ // component, since it may have been filled in by a malicious app
+ mOriginalIntent.prepareToEnterProcess(0, source);
}
if (mContentUserHint != UserHandle.USER_CURRENT) {
@@ -11920,9 +11942,7 @@
}
}
- if (fromProtectedComponent) {
- mLocalFlags |= LOCAL_FLAG_FROM_PROTECTED_COMPONENT;
- }
+ mLocalFlags |= localFlags;
// Special attribution fix-up logic for any BluetoothDevice extras
// passed via Bluetooth intents
diff --git a/core/java/android/content/RestrictionsManager.java b/core/java/android/content/RestrictionsManager.java
index 885eb70..ffd80ea 100644
--- a/core/java/android/content/RestrictionsManager.java
+++ b/core/java/android/content/RestrictionsManager.java
@@ -16,6 +16,8 @@
package android.content;
+import static android.content.Intent.LOCAL_FLAG_FROM_SYSTEM;
+
import android.annotation.SystemService;
import android.app.Activity;
import android.app.admin.DevicePolicyManager;
@@ -487,14 +489,19 @@
}
public Intent createLocalApprovalIntent() {
+ Intent result = null;
try {
if (mService != null) {
- return mService.createLocalApprovalIntent();
+ result = mService.createLocalApprovalIntent();
+ if (result != null) {
+ result.prepareToEnterProcess(LOCAL_FLAG_FROM_SYSTEM,
+ mContext.getAttributionSource());
+ }
}
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
- return null;
+ return result;
}
/**
diff --git a/core/java/android/content/pm/ShortcutManager.java b/core/java/android/content/pm/ShortcutManager.java
index 70b90e6..e48a02a 100644
--- a/core/java/android/content/pm/ShortcutManager.java
+++ b/core/java/android/content/pm/ShortcutManager.java
@@ -15,6 +15,8 @@
*/
package android.content.pm;
+import static android.content.Intent.LOCAL_FLAG_FROM_SYSTEM;
+
import android.Manifest;
import android.annotation.IntDef;
import android.annotation.NonNull;
@@ -628,7 +630,12 @@
try {
mService.createShortcutResultIntent(mContext.getPackageName(),
shortcut, injectMyUserId(), ret);
- return getFutureOrThrow(ret);
+ Intent result = getFutureOrThrow(ret);
+ if (result != null) {
+ result.prepareToEnterProcess(LOCAL_FLAG_FROM_SYSTEM,
+ mContext.getAttributionSource());
+ }
+ return result;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index 9fcf44e..ccec67e 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -15,6 +15,7 @@
package android.telecom;
import static android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE;
+import static android.content.Intent.LOCAL_FLAG_FROM_SYSTEM;
import android.Manifest;
import android.annotation.IntDef;
@@ -2417,6 +2418,10 @@
if (service != null) {
try {
result = service.createManageBlockedNumbersIntent(mContext.getPackageName());
+ if (result != null) {
+ result.prepareToEnterProcess(LOCAL_FLAG_FROM_SYSTEM,
+ mContext.getAttributionSource());
+ }
} catch (RemoteException e) {
Log.e(TAG, "Error calling ITelecomService#createManageBlockedNumbersIntent", e);
}
@@ -2438,7 +2443,12 @@
ITelecomService service = getTelecomService();
if (service != null) {
try {
- return service.createLaunchEmergencyDialerIntent(number);
+ Intent result = service.createLaunchEmergencyDialerIntent(number);
+ if (result != null) {
+ result.prepareToEnterProcess(LOCAL_FLAG_FROM_SYSTEM,
+ mContext.getAttributionSource());
+ }
+ return result;
} catch (RemoteException e) {
Log.e(TAG, "Error createLaunchEmergencyDialerIntent", e);
}