summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeff Sharkey <jsharkey@android.com>2013-04-03 23:28:07 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2013-04-03 23:28:07 +0000
commit0f8e8b03ebb35040c299079adc1c351f37ce4885 (patch)
tree19158f23cbd5b9dff30b7f6bedea8bba81f9ecb7
parent0d17aaa543f393c6c792f0b0d8ec5cb38ff1f71e (diff)
parenta14acd20b8d563319ea1a5974dca0e9a29f0aaef (diff)
downloadframeworks_base-0f8e8b03ebb35040c299079adc1c351f37ce4885.zip
frameworks_base-0f8e8b03ebb35040c299079adc1c351f37ce4885.tar.gz
frameworks_base-0f8e8b03ebb35040c299079adc1c351f37ce4885.tar.bz2
Merge "Warn when exposing file:// Uris beyond a process." into jb-mr2-dev
-rw-r--r--api/current.txt1
-rw-r--r--core/java/android/app/Activity.java16
-rw-r--r--core/java/android/app/ContextImpl.java37
-rw-r--r--core/java/android/app/Instrumentation.java9
-rw-r--r--core/java/android/app/NotificationManager.java7
-rw-r--r--core/java/android/app/PendingIntent.java14
-rw-r--r--core/java/android/content/BroadcastReceiver.java2
-rw-r--r--core/java/android/content/ClipData.java19
-rw-r--r--core/java/android/content/ClipboardManager.java4
-rw-r--r--core/java/android/content/Intent.java27
-rw-r--r--core/java/android/net/Uri.java13
-rw-r--r--core/java/android/os/StrictMode.java35
-rw-r--r--core/java/android/widget/RemoteViews.java10
13 files changed, 155 insertions, 39 deletions
diff --git a/api/current.txt b/api/current.txt
index e001e1a..b9c67c4 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -16940,6 +16940,7 @@ package android.os {
method public android.os.StrictMode.VmPolicy build();
method public android.os.StrictMode.VmPolicy.Builder detectActivityLeaks();
method public android.os.StrictMode.VmPolicy.Builder detectAll();
+ method public android.os.StrictMode.VmPolicy.Builder detectFileUriExposure();
method public android.os.StrictMode.VmPolicy.Builder detectLeakedClosableObjects();
method public android.os.StrictMode.VmPolicy.Builder detectLeakedRegistrationObjects();
method public android.os.StrictMode.VmPolicy.Builder detectLeakedSqlLiteObjects();
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 87c2d8c..31074e2 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -3513,7 +3513,8 @@ public class Activity extends ContextThemeWrapper
try {
String resolvedType = null;
if (fillInIntent != null) {
- fillInIntent.setAllowFds(false);
+ fillInIntent.migrateExtraStreamToClipData();
+ fillInIntent.prepareToLeaveProcess();
resolvedType = fillInIntent.resolveTypeIfNeeded(getContentResolver());
}
int result = ActivityManagerNative.getDefault()
@@ -3738,7 +3739,8 @@ public class Activity extends ContextThemeWrapper
if (mParent == null) {
int result = ActivityManager.START_RETURN_INTENT_TO_CALLER;
try {
- intent.setAllowFds(false);
+ intent.migrateExtraStreamToClipData();
+ intent.prepareToLeaveProcess();
result = ActivityManagerNative.getDefault()
.startActivity(mMainThread.getApplicationThread(), getBasePackageName(),
intent, intent.resolveTypeIfNeeded(getContentResolver()),
@@ -3808,7 +3810,8 @@ public class Activity extends ContextThemeWrapper
public boolean startNextMatchingActivity(Intent intent, Bundle options) {
if (mParent == null) {
try {
- intent.setAllowFds(false);
+ intent.migrateExtraStreamToClipData();
+ intent.prepareToLeaveProcess();
return ActivityManagerNative.getDefault()
.startNextMatchingActivity(mToken, intent, options);
} catch (RemoteException e) {
@@ -4162,7 +4165,7 @@ public class Activity extends ContextThemeWrapper
if (false) Log.v(TAG, "Finishing self: token=" + mToken);
try {
if (resultData != null) {
- resultData.setAllowFds(false);
+ resultData.prepareToLeaveProcess();
}
if (ActivityManagerNative.getDefault()
.finishActivity(mToken, resultCode, resultData)) {
@@ -4314,7 +4317,7 @@ public class Activity extends ContextThemeWrapper
int flags) {
String packageName = getPackageName();
try {
- data.setAllowFds(false);
+ data.prepareToLeaveProcess();
IIntentSender target =
ActivityManagerNative.getDefault().getIntentSender(
ActivityManager.INTENT_SENDER_ACTIVITY_RESULT, packageName,
@@ -4993,9 +4996,10 @@ public class Activity extends ContextThemeWrapper
resultData = mResultData;
}
if (resultData != null) {
- resultData.setAllowFds(false);
+ resultData.prepareToLeaveProcess();
}
try {
+ upIntent.prepareToLeaveProcess();
return ActivityManagerNative.getDefault().navigateUpTo(mToken, upIntent,
resultCode, resultData);
} catch (RemoteException e) {
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 459e49c..9bf8830 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -1020,7 +1020,8 @@ class ContextImpl extends Context {
try {
String resolvedType = null;
if (fillInIntent != null) {
- fillInIntent.setAllowFds(false);
+ fillInIntent.migrateExtraStreamToClipData();
+ fillInIntent.prepareToLeaveProcess();
resolvedType = fillInIntent.resolveTypeIfNeeded(getContentResolver());
}
int result = ActivityManagerNative.getDefault()
@@ -1040,7 +1041,7 @@ class ContextImpl extends Context {
warnIfCallingFromSystemProcess();
String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
try {
- intent.setAllowFds(false);
+ intent.prepareToLeaveProcess();
ActivityManagerNative.getDefault().broadcastIntent(
mMainThread.getApplicationThread(), intent, resolvedType, null,
Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, false, false,
@@ -1054,7 +1055,7 @@ class ContextImpl extends Context {
warnIfCallingFromSystemProcess();
String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
try {
- intent.setAllowFds(false);
+ intent.prepareToLeaveProcess();
ActivityManagerNative.getDefault().broadcastIntent(
mMainThread.getApplicationThread(), intent, resolvedType, null,
Activity.RESULT_OK, null, null, receiverPermission, AppOpsManager.OP_NONE,
@@ -1068,7 +1069,7 @@ class ContextImpl extends Context {
warnIfCallingFromSystemProcess();
String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
try {
- intent.setAllowFds(false);
+ intent.prepareToLeaveProcess();
ActivityManagerNative.getDefault().broadcastIntent(
mMainThread.getApplicationThread(), intent, resolvedType, null,
Activity.RESULT_OK, null, null, receiverPermission, appOp, false, false,
@@ -1083,7 +1084,7 @@ class ContextImpl extends Context {
warnIfCallingFromSystemProcess();
String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
try {
- intent.setAllowFds(false);
+ intent.prepareToLeaveProcess();
ActivityManagerNative.getDefault().broadcastIntent(
mMainThread.getApplicationThread(), intent, resolvedType, null,
Activity.RESULT_OK, null, null, receiverPermission, AppOpsManager.OP_NONE, true, false,
@@ -1126,7 +1127,7 @@ class ContextImpl extends Context {
}
String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
try {
- intent.setAllowFds(false);
+ intent.prepareToLeaveProcess();
ActivityManagerNative.getDefault().broadcastIntent(
mMainThread.getApplicationThread(), intent, resolvedType, rd,
initialCode, initialData, initialExtras, receiverPermission, appOp,
@@ -1139,7 +1140,7 @@ class ContextImpl extends Context {
public void sendBroadcastAsUser(Intent intent, UserHandle user) {
String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
try {
- intent.setAllowFds(false);
+ intent.prepareToLeaveProcess();
ActivityManagerNative.getDefault().broadcastIntent(mMainThread.getApplicationThread(),
intent, resolvedType, null, Activity.RESULT_OK, null, null, null,
AppOpsManager.OP_NONE, false, false, user.getIdentifier());
@@ -1152,7 +1153,7 @@ class ContextImpl extends Context {
String receiverPermission) {
String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
try {
- intent.setAllowFds(false);
+ intent.prepareToLeaveProcess();
ActivityManagerNative.getDefault().broadcastIntent(
mMainThread.getApplicationThread(), intent, resolvedType, null,
Activity.RESULT_OK, null, null, receiverPermission, AppOpsManager.OP_NONE, false, false,
@@ -1184,7 +1185,7 @@ class ContextImpl extends Context {
}
String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
try {
- intent.setAllowFds(false);
+ intent.prepareToLeaveProcess();
ActivityManagerNative.getDefault().broadcastIntent(
mMainThread.getApplicationThread(), intent, resolvedType, rd,
initialCode, initialData, initialExtras, receiverPermission,
@@ -1198,7 +1199,7 @@ class ContextImpl extends Context {
warnIfCallingFromSystemProcess();
String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
try {
- intent.setAllowFds(false);
+ intent.prepareToLeaveProcess();
ActivityManagerNative.getDefault().broadcastIntent(
mMainThread.getApplicationThread(), intent, resolvedType, null,
Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, false, true,
@@ -1232,7 +1233,7 @@ class ContextImpl extends Context {
}
String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
try {
- intent.setAllowFds(false);
+ intent.prepareToLeaveProcess();
ActivityManagerNative.getDefault().broadcastIntent(
mMainThread.getApplicationThread(), intent, resolvedType, rd,
initialCode, initialData, initialExtras, null,
@@ -1249,7 +1250,7 @@ class ContextImpl extends Context {
intent.setDataAndType(intent.getData(), resolvedType);
}
try {
- intent.setAllowFds(false);
+ intent.prepareToLeaveProcess();
ActivityManagerNative.getDefault().unbroadcastIntent(
mMainThread.getApplicationThread(), intent, getUserId());
} catch (RemoteException e) {
@@ -1260,7 +1261,7 @@ class ContextImpl extends Context {
public void sendStickyBroadcastAsUser(Intent intent, UserHandle user) {
String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
try {
- intent.setAllowFds(false);
+ intent.prepareToLeaveProcess();
ActivityManagerNative.getDefault().broadcastIntent(
mMainThread.getApplicationThread(), intent, resolvedType, null,
Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, false, true, user.getIdentifier());
@@ -1292,7 +1293,7 @@ class ContextImpl extends Context {
}
String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
try {
- intent.setAllowFds(false);
+ intent.prepareToLeaveProcess();
ActivityManagerNative.getDefault().broadcastIntent(
mMainThread.getApplicationThread(), intent, resolvedType, rd,
initialCode, initialData, initialExtras, null,
@@ -1309,7 +1310,7 @@ class ContextImpl extends Context {
intent.setDataAndType(intent.getData(), resolvedType);
}
try {
- intent.setAllowFds(false);
+ intent.prepareToLeaveProcess();
ActivityManagerNative.getDefault().unbroadcastIntent(
mMainThread.getApplicationThread(), intent, user.getIdentifier());
} catch (RemoteException e) {
@@ -1393,7 +1394,7 @@ class ContextImpl extends Context {
@Override
public ComponentName startServiceAsUser(Intent service, UserHandle user) {
try {
- service.setAllowFds(false);
+ service.prepareToLeaveProcess();
ComponentName cn = ActivityManagerNative.getDefault().startService(
mMainThread.getApplicationThread(), service,
service.resolveTypeIfNeeded(getContentResolver()), user.getIdentifier());
@@ -1417,7 +1418,7 @@ class ContextImpl extends Context {
@Override
public boolean stopServiceAsUser(Intent service, UserHandle user) {
try {
- service.setAllowFds(false);
+ service.prepareToLeaveProcess();
int res = ActivityManagerNative.getDefault().stopService(
mMainThread.getApplicationThread(), service,
service.resolveTypeIfNeeded(getContentResolver()), user.getIdentifier());
@@ -1459,7 +1460,7 @@ class ContextImpl extends Context {
< android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
flags |= BIND_WAIVE_PRIORITY;
}
- service.setAllowFds(false);
+ service.prepareToLeaveProcess();
int res = ActivityManagerNative.getDefault().bindService(
mMainThread.getApplicationThread(), getActivityToken(),
service, service.resolveTypeIfNeeded(getContentResolver()),
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index e7bf305..e0dfb25 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -1410,8 +1410,8 @@ public class Instrumentation {
}
}
try {
- intent.setAllowFds(false);
intent.migrateExtraStreamToClipData();
+ intent.prepareToLeaveProcess();
int result = ActivityManagerNative.getDefault()
.startActivity(whoThread, who.getBasePackageName(), intent,
intent.resolveTypeIfNeeded(who.getContentResolver()),
@@ -1467,7 +1467,8 @@ public class Instrumentation {
try {
String[] resolvedTypes = new String[intents.length];
for (int i=0; i<intents.length; i++) {
- intents[i].setAllowFds(false);
+ intents[i].migrateExtraStreamToClipData();
+ intents[i].prepareToLeaveProcess();
resolvedTypes[i] = intents[i].resolveTypeIfNeeded(who.getContentResolver());
}
int result = ActivityManagerNative.getDefault()
@@ -1526,8 +1527,8 @@ public class Instrumentation {
}
}
try {
- intent.setAllowFds(false);
intent.migrateExtraStreamToClipData();
+ intent.prepareToLeaveProcess();
int result = ActivityManagerNative.getDefault()
.startActivity(whoThread, who.getBasePackageName(), intent,
intent.resolveTypeIfNeeded(who.getContentResolver()),
@@ -1586,8 +1587,8 @@ public class Instrumentation {
}
}
try {
- intent.setAllowFds(false);
intent.migrateExtraStreamToClipData();
+ intent.prepareToLeaveProcess();
int result = ActivityManagerNative.getDefault()
.startActivityAsUser(whoThread, who.getBasePackageName(), intent,
intent.resolveTypeIfNeeded(who.getContentResolver()),
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index 5e69128..dbafc78 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -21,6 +21,7 @@ import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.StrictMode;
import android.os.UserHandle;
import android.util.Log;
@@ -126,6 +127,9 @@ public class NotificationManager
String pkg = mContext.getPackageName();
if (notification.sound != null) {
notification.sound = notification.sound.getCanonicalUri();
+ if (StrictMode.vmFileUriExposureEnabled()) {
+ notification.sound.checkFileUriExposed("Notification.sound");
+ }
}
if (localLOGV) Log.v(TAG, pkg + ": notify(" + id + ", " + notification + ")");
try {
@@ -148,6 +152,9 @@ public class NotificationManager
String pkg = mContext.getPackageName();
if (notification.sound != null) {
notification.sound = notification.sound.getCanonicalUri();
+ if (StrictMode.vmFileUriExposureEnabled()) {
+ notification.sound.checkFileUriExposed("Notification.sound");
+ }
}
if (localLOGV) Log.v(TAG, pkg + ": notify(" + id + ", " + notification + ")");
try {
diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java
index 20114cc..25c790f 100644
--- a/core/java/android/app/PendingIntent.java
+++ b/core/java/android/app/PendingIntent.java
@@ -260,8 +260,8 @@ public final class PendingIntent implements Parcelable {
String resolvedType = intent != null ? intent.resolveTypeIfNeeded(
context.getContentResolver()) : null;
try {
- intent.setAllowFds(false);
intent.migrateExtraStreamToClipData();
+ intent.prepareToLeaveProcess();
IIntentSender target =
ActivityManagerNative.getDefault().getIntentSender(
ActivityManager.INTENT_SENDER_ACTIVITY, packageName,
@@ -285,8 +285,8 @@ public final class PendingIntent implements Parcelable {
String resolvedType = intent != null ? intent.resolveTypeIfNeeded(
context.getContentResolver()) : null;
try {
- intent.setAllowFds(false);
intent.migrateExtraStreamToClipData();
+ intent.prepareToLeaveProcess();
IIntentSender target =
ActivityManagerNative.getDefault().getIntentSender(
ActivityManager.INTENT_SENDER_ACTIVITY, packageName,
@@ -401,7 +401,8 @@ public final class PendingIntent implements Parcelable {
String packageName = context.getPackageName();
String[] resolvedTypes = new String[intents.length];
for (int i=0; i<intents.length; i++) {
- intents[i].setAllowFds(false);
+ intents[i].migrateExtraStreamToClipData();
+ intents[i].prepareToLeaveProcess();
resolvedTypes[i] = intents[i].resolveTypeIfNeeded(context.getContentResolver());
}
try {
@@ -426,7 +427,8 @@ public final class PendingIntent implements Parcelable {
String packageName = context.getPackageName();
String[] resolvedTypes = new String[intents.length];
for (int i=0; i<intents.length; i++) {
- intents[i].setAllowFds(false);
+ intents[i].migrateExtraStreamToClipData();
+ intents[i].prepareToLeaveProcess();
resolvedTypes[i] = intents[i].resolveTypeIfNeeded(context.getContentResolver());
}
try {
@@ -482,7 +484,7 @@ public final class PendingIntent implements Parcelable {
String resolvedType = intent != null ? intent.resolveTypeIfNeeded(
context.getContentResolver()) : null;
try {
- intent.setAllowFds(false);
+ intent.prepareToLeaveProcess();
IIntentSender target =
ActivityManagerNative.getDefault().getIntentSender(
ActivityManager.INTENT_SENDER_BROADCAST, packageName,
@@ -526,7 +528,7 @@ public final class PendingIntent implements Parcelable {
String resolvedType = intent != null ? intent.resolveTypeIfNeeded(
context.getContentResolver()) : null;
try {
- intent.setAllowFds(false);
+ intent.prepareToLeaveProcess();
IIntentSender target =
ActivityManagerNative.getDefault().getIntentSender(
ActivityManager.INTENT_SENDER_SERVICE, packageName,
diff --git a/core/java/android/content/BroadcastReceiver.java b/core/java/android/content/BroadcastReceiver.java
index 4f42d50..9a32fdf 100644
--- a/core/java/android/content/BroadcastReceiver.java
+++ b/core/java/android/content/BroadcastReceiver.java
@@ -520,7 +520,7 @@ public abstract class BroadcastReceiver {
IActivityManager am = ActivityManagerNative.getDefault();
IBinder binder = null;
try {
- service.setAllowFds(false);
+ service.prepareToLeaveProcess();
binder = am.peekService(service, service.resolveTypeIfNeeded(
myContext.getContentResolver()));
} catch (RemoteException e) {
diff --git a/core/java/android/content/ClipData.java b/core/java/android/content/ClipData.java
index 88f1a3d..50c4fed 100644
--- a/core/java/android/content/ClipData.java
+++ b/core/java/android/content/ClipData.java
@@ -21,6 +21,7 @@ import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Parcel;
import android.os.Parcelable;
+import android.os.StrictMode;
import android.text.Html;
import android.text.Spannable;
import android.text.SpannableStringBuilder;
@@ -790,6 +791,24 @@ public class ClipData implements Parcelable {
return mItems.get(index);
}
+ /**
+ * Prepare this {@link ClipData} to leave an app process.
+ *
+ * @hide
+ */
+ public void prepareToLeaveProcess() {
+ final int size = mItems.size();
+ for (int i = 0; i < size; i++) {
+ final Item item = mItems.get(i);
+ if (item.mIntent != null) {
+ item.mIntent.prepareToLeaveProcess();
+ }
+ if (item.mUri != null && StrictMode.vmFileUriExposureEnabled()) {
+ item.mUri.checkFileUriExposed("ClipData.Item.getUri()");
+ }
+ }
+ }
+
@Override
public String toString() {
StringBuilder b = new StringBuilder(128);
diff --git a/core/java/android/content/ClipboardManager.java b/core/java/android/content/ClipboardManager.java
index 88a4229..69f9d4a 100644
--- a/core/java/android/content/ClipboardManager.java
+++ b/core/java/android/content/ClipboardManager.java
@@ -22,6 +22,7 @@ import android.os.RemoteException;
import android.os.Handler;
import android.os.IBinder;
import android.os.ServiceManager;
+import android.os.StrictMode;
import android.util.Log;
import java.util.ArrayList;
@@ -118,6 +119,9 @@ public class ClipboardManager extends android.text.ClipboardManager {
*/
public void setPrimaryClip(ClipData clip) {
try {
+ if (clip != null) {
+ clip.prepareToLeaveProcess();
+ }
getService().setPrimaryClip(clip, mContext.getBasePackageName());
} catch (RemoteException e) {
}
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index c9b9a1a..97ad7dd 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -32,6 +32,7 @@ import android.os.Bundle;
import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
+import android.os.StrictMode;
import android.util.AttributeSet;
import android.util.Log;
@@ -6966,6 +6967,32 @@ public class Intent implements Parcelable, Cloneable {
}
/**
+ * Prepare this {@link Intent} to leave an app process.
+ *
+ * @hide
+ */
+ public void prepareToLeaveProcess() {
+ setAllowFds(false);
+
+ if (mSelector != null) {
+ mSelector.prepareToLeaveProcess();
+ }
+ if (mClipData != null) {
+ mClipData.prepareToLeaveProcess();
+ }
+
+ if (mData != null && StrictMode.vmFileUriExposureEnabled()) {
+ // There are several ACTION_MEDIA_* broadcasts that send file://
+ // Uris, so only check common actions.
+ if (ACTION_VIEW.equals(mAction) ||
+ ACTION_EDIT.equals(mAction) ||
+ ACTION_ATTACH_DATA.equals(mAction)) {
+ mData.checkFileUriExposed("Intent.getData()");
+ }
+ }
+ }
+
+ /**
* Migrate any {@link #EXTRA_STREAM} in {@link #ACTION_SEND} and
* {@link #ACTION_SEND_MULTIPLE} to {@link ClipData}. Also inspects nested
* intents in {@link #ACTION_CHOOSER}.
diff --git a/core/java/android/net/Uri.java b/core/java/android/net/Uri.java
index cc6903d..4b022d9 100644
--- a/core/java/android/net/Uri.java
+++ b/core/java/android/net/Uri.java
@@ -20,6 +20,7 @@ import android.os.Environment;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.Environment.UserEnvironment;
+import android.os.StrictMode;
import android.util.Log;
import java.io.File;
import java.io.IOException;
@@ -2326,4 +2327,16 @@ public abstract class Uri implements Parcelable, Comparable<Uri> {
return this;
}
}
+
+ /**
+ * If this is a {@code file://} Uri, it will be reported to
+ * {@link StrictMode}.
+ *
+ * @hide
+ */
+ public void checkFileUriExposed(String location) {
+ if ("file".equals(getScheme())) {
+ StrictMode.onFileUriExposed(location);
+ }
+ }
}
diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java
index f682abe..d2943ab 100644
--- a/core/java/android/os/StrictMode.java
+++ b/core/java/android/os/StrictMode.java
@@ -203,10 +203,15 @@ public final class StrictMode {
*/
public static final int DETECT_VM_REGISTRATION_LEAKS = 0x2000; // for VmPolicy
+ /**
+ * @hide
+ */
+ private static final int DETECT_VM_FILE_URI_EXPOSURE = 0x4000; // for VmPolicy
+
private static final int ALL_VM_DETECT_BITS =
DETECT_VM_CURSOR_LEAKS | DETECT_VM_CLOSABLE_LEAKS |
DETECT_VM_ACTIVITY_LEAKS | DETECT_VM_INSTANCE_LEAKS |
- DETECT_VM_REGISTRATION_LEAKS;
+ DETECT_VM_REGISTRATION_LEAKS | DETECT_VM_FILE_URI_EXPOSURE;
/**
* @hide
@@ -628,7 +633,8 @@ public final class StrictMode {
*/
public Builder detectAll() {
return enable(DETECT_VM_ACTIVITY_LEAKS | DETECT_VM_CURSOR_LEAKS
- | DETECT_VM_CLOSABLE_LEAKS | DETECT_VM_REGISTRATION_LEAKS);
+ | DETECT_VM_CLOSABLE_LEAKS | DETECT_VM_REGISTRATION_LEAKS
+ | DETECT_VM_FILE_URI_EXPOSURE);
}
/**
@@ -666,6 +672,16 @@ public final class StrictMode {
}
/**
+ * Detect when a {@code file://} {@link Uri} is exposed beyond this
+ * app. The receiving app may not have access to the sent path.
+ * Instead, when sharing files between apps, {@code content://}
+ * should be used with permission grants.
+ */
+ public Builder detectFileUriExposure() {
+ return enable(DETECT_VM_FILE_URI_EXPOSURE);
+ }
+
+ /**
* Crashes the whole process on violation. This penalty runs at
* the end of all enabled penalties so yo you'll still get
* your logging or other violations before the process dies.
@@ -1524,6 +1540,13 @@ public final class StrictMode {
/**
* @hide
*/
+ public static boolean vmFileUriExposureEnabled() {
+ return (sVmPolicyMask & DETECT_VM_FILE_URI_EXPOSURE) != 0;
+ }
+
+ /**
+ * @hide
+ */
public static void onSqliteObjectLeaked(String message, Throwable originStack) {
onVmPolicyViolation(message, originStack);
}
@@ -1549,6 +1572,14 @@ public final class StrictMode {
onVmPolicyViolation(null, originStack);
}
+ /**
+ * @hide
+ */
+ public static void onFileUriExposed(String location) {
+ final String message = "file:// Uri exposed through " + location;
+ onVmPolicyViolation(message, new Throwable(message));
+ }
+
// Map from VM violation fingerprint to uptime millis.
private static final HashMap<Integer, Long> sLastVmViolationTime = new HashMap<Integer, Long>();
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 79fc51e..83e2e79 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -34,6 +34,7 @@ import android.os.Build;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
+import android.os.StrictMode;
import android.os.UserHandle;
import android.text.TextUtils;
import android.util.Log;
@@ -2263,8 +2264,13 @@ public class RemoteViews implements Parcelable, Filter {
* @param value The value to pass to the method.
*/
public void setUri(int viewId, String methodName, Uri value) {
- // Resolve any filesystem path before sending remotely
- value = value.getCanonicalUri();
+ if (value != null) {
+ // Resolve any filesystem path before sending remotely
+ value = value.getCanonicalUri();
+ if (StrictMode.vmFileUriExposureEnabled()) {
+ value.checkFileUriExposed("RemoteViews.setUri()");
+ }
+ }
addAction(new ReflectionAction(viewId, methodName, ReflectionAction.URI, value));
}