summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--api/current.txt4
-rw-r--r--core/java/android/app/Activity.java24
-rw-r--r--core/java/android/app/Service.java14
-rw-r--r--core/java/android/content/ClipData.java84
-rw-r--r--core/java/android/content/ClipDescription.java33
-rw-r--r--core/java/android/content/Intent.java133
-rw-r--r--services/java/com/android/server/AlarmManagerService.java3
-rw-r--r--services/java/com/android/server/am/ActivityManagerService.java128
-rw-r--r--services/java/com/android/server/am/ActivityRecord.java33
-rw-r--r--services/java/com/android/server/am/ActivityStack.java4
-rw-r--r--services/java/com/android/server/am/IntentBindRecord.java4
-rw-r--r--services/java/com/android/server/am/PendingIntentRecord.java4
-rw-r--r--services/java/com/android/server/am/ServiceRecord.java14
-rw-r--r--services/java/com/android/server/am/TaskRecord.java4
14 files changed, 397 insertions, 89 deletions
diff --git a/api/current.txt b/api/current.txt
index dbe57d1e31a5..f79df94158b0 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -4761,6 +4761,7 @@ package android.content {
public class ClipData implements android.os.Parcelable {
ctor public ClipData(java.lang.CharSequence, java.lang.String[], android.content.ClipData.Item);
ctor public ClipData(android.content.ClipDescription, android.content.ClipData.Item);
+ ctor public ClipData(android.content.ClipData);
method public void addItem(android.content.ClipData.Item);
method public int describeContents();
method public android.content.ClipDescription getDescription();
@@ -5378,6 +5379,7 @@ package android.content {
method public java.lang.CharSequence[] getCharSequenceArrayExtra(java.lang.String);
method public java.util.ArrayList<java.lang.CharSequence> getCharSequenceArrayListExtra(java.lang.String);
method public java.lang.CharSequence getCharSequenceExtra(java.lang.String);
+ method public android.content.ClipData getClipData();
method public android.content.ComponentName getComponent();
method public android.net.Uri getData();
method public java.lang.String getDataString();
@@ -5461,6 +5463,7 @@ package android.content {
method public android.content.Intent setClass(android.content.Context, java.lang.Class<?>);
method public android.content.Intent setClassName(android.content.Context, java.lang.String);
method public android.content.Intent setClassName(java.lang.String, java.lang.String);
+ method public void setClipData(android.content.ClipData);
method public android.content.Intent setComponent(android.content.ComponentName);
method public android.content.Intent setData(android.net.Uri);
method public android.content.Intent setDataAndNormalize(android.net.Uri);
@@ -5646,6 +5649,7 @@ package android.content {
field public static final java.lang.String EXTRA_UID = "android.intent.extra.UID";
field public static final int FILL_IN_ACTION = 1; // 0x1
field public static final int FILL_IN_CATEGORIES = 4; // 0x4
+ field public static final int FILL_IN_CLIP_DATA = 128; // 0x80
field public static final int FILL_IN_COMPONENT = 8; // 0x8
field public static final int FILL_IN_DATA = 2; // 0x2
field public static final int FILL_IN_PACKAGE = 16; // 0x10
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 8e8d37d645c9..f8954315630b 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -570,7 +570,18 @@ import java.util.HashMap;
* tag. By doing so, other applications will need to declare a corresponding
* {@link android.R.styleable#AndroidManifestUsesPermission &lt;uses-permission&gt;}
* element in their own manifest to be able to start that activity.
- *
+ *
+ * <p>When starting an Activity you can set {@link Intent#FLAG_GRANT_READ_URI_PERMISSION
+ * Intent.FLAG_GRANT_READ_URI_PERMISSION} and/or {@link Intent#FLAG_GRANT_WRITE_URI_PERMISSION
+ * Intent.FLAG_GRANT_WRITE_URI_PERMISSION} on the Intent. This will grant the
+ * Activity access to the specific URIs in the Intent. Access will remain
+ * until the Activity has finished (it will remain across the hosting
+ * process being killed and other temporary destruction). As of
+ * {@link android.os.Build.VERSION_CODES#GINGERBREAD}, if the Activity
+ * was already created and a new Intent is being delivered to
+ * {@link #onNewIntent(Intent)}, any newly granted URI permissions will be added
+ * to the existing ones it holds.
+ *
* <p>See the <a href="{@docRoot}guide/topics/security/security.html">Security and Permissions</a>
* document for more information on permissions and security in general.
*
@@ -3549,7 +3560,16 @@ public class Activity extends ContextThemeWrapper
/**
* Call this to set the result that your activity will return to its
* caller.
- *
+ *
+ * <p>As of {@link android.os.Build.VERSION_CODES#GINGERBREAD}, the Intent
+ * you supply here can have {@link Intent#FLAG_GRANT_READ_URI_PERMISSION
+ * Intent.FLAG_GRANT_READ_URI_PERMISSION} and/or {@link Intent#FLAG_GRANT_WRITE_URI_PERMISSION
+ * Intent.FLAG_GRANT_WRITE_URI_PERMISSION} set. This will grant the
+ * Activity receiving the result access to the specific URIs in the Intent.
+ * Access will remain until the Activity has finished (it will remain across the hosting
+ * process being killed and other temporary destruction) and will be added
+ * to any existing set of URI permissions it already holds.
+ *
* @param resultCode The result code to propagate back to the originating
* activity, often RESULT_CANCELED or RESULT_OK
* @param data The data to propagate back to the originating activity.
diff --git a/core/java/android/app/Service.java b/core/java/android/app/Service.java
index 35bd8c08a713..be4b8af6fb49 100644
--- a/core/java/android/app/Service.java
+++ b/core/java/android/app/Service.java
@@ -163,7 +163,19 @@ import java.io.PrintWriter;
* {@link android.R.styleable#AndroidManifestUsesPermission &lt;uses-permission&gt;}
* element in their own manifest to be able to start, stop, or bind to
* the service.
- *
+ *
+ * <p>As of {@link android.os.Build.VERSION_CODES#GINGERBREAD}, when using
+ * {@link Context#startService(Intent) Context.startService(Intent)}, you can
+ * also set {@link Intent#FLAG_GRANT_READ_URI_PERMISSION
+ * Intent.FLAG_GRANT_READ_URI_PERMISSION} and/or {@link Intent#FLAG_GRANT_WRITE_URI_PERMISSION
+ * Intent.FLAG_GRANT_WRITE_URI_PERMISSION} on the Intent. This will grant the
+ * Service temporary access to the specific URIs in the Intent. Access will
+ * remain until the Service has called {@link #stopSelf(int)} for that start
+ * command or a later one, or until the Service has been completely stopped.
+ * This works for granting access to the other apps that have not requested
+ * the permission protecting the Service, or even when the Service is not
+ * exported at all.
+ *
* <p>In addition, a service can protect individual IPC calls into it with
* permissions, by calling the
* {@link #checkCallingPermission}
diff --git a/core/java/android/content/ClipData.java b/core/java/android/content/ClipData.java
index a8b1bf47d624..a655dd424aa9 100644
--- a/core/java/android/content/ClipData.java
+++ b/core/java/android/content/ClipData.java
@@ -153,7 +153,7 @@ public class ClipData implements Parcelable {
final Bitmap mIcon;
- final ArrayList<Item> mItems = new ArrayList<Item>();
+ final ArrayList<Item> mItems;
/**
* Description of a single item in a ClippedData.
@@ -321,6 +321,33 @@ public class ClipData implements Parcelable {
return "";
}
//END_INCLUDE(coerceToText)
+
+ @Override
+ public String toString() {
+ StringBuilder b = new StringBuilder(128);
+
+ b.append("ClipData.Item { ");
+ toShortString(b);
+ b.append(" }");
+
+ return b.toString();
+ }
+
+ /** @hide */
+ public void toShortString(StringBuilder b) {
+ if (mText != null) {
+ b.append("T:");
+ b.append(mText);
+ } else if (mUri != null) {
+ b.append("U:");
+ b.append(mUri);
+ } else if (mIntent != null) {
+ b.append("I:");
+ mIntent.toShortString(b, true, true, true, true);
+ } else {
+ b.append("NULL");
+ }
+ }
}
/**
@@ -336,6 +363,7 @@ public class ClipData implements Parcelable {
throw new NullPointerException("item is null");
}
mIcon = null;
+ mItems = new ArrayList<Item>();
mItems.add(item);
}
@@ -351,10 +379,23 @@ public class ClipData implements Parcelable {
throw new NullPointerException("item is null");
}
mIcon = null;
+ mItems = new ArrayList<Item>();
mItems.add(item);
}
/**
+ * Create a new clip that is a copy of another clip. This does a deep-copy
+ * of all items in the clip.
+ *
+ * @param other The existing ClipData that is to be copied.
+ */
+ public ClipData(ClipData other) {
+ mClipDescription = other.mClipDescription;
+ mIcon = other.mIcon;
+ mItems = new ArrayList<Item>(other.mItems);
+ }
+
+ /**
* Create a new ClipData holding data of the type
* {@link ClipDescription#MIMETYPE_TEXT_PLAIN}.
*
@@ -475,6 +516,46 @@ public class ClipData implements Parcelable {
}
@Override
+ public String toString() {
+ StringBuilder b = new StringBuilder(128);
+
+ b.append("ClipData { ");
+ toShortString(b);
+ b.append(" }");
+
+ return b.toString();
+ }
+
+ /** @hide */
+ public void toShortString(StringBuilder b) {
+ boolean first;
+ if (mClipDescription != null) {
+ first = !mClipDescription.toShortString(b);
+ } else {
+ first = true;
+ }
+ if (mIcon != null) {
+ if (!first) {
+ b.append(' ');
+ }
+ first = false;
+ b.append("I:");
+ b.append(mIcon.getWidth());
+ b.append('x');
+ b.append(mIcon.getHeight());
+ }
+ for (int i=0; i<mItems.size(); i++) {
+ if (!first) {
+ b.append(' ');
+ }
+ first = false;
+ b.append('{');
+ mItems.get(i).toShortString(b);
+ b.append('}');
+ }
+ }
+
+ @Override
public int describeContents() {
return 0;
}
@@ -515,6 +596,7 @@ public class ClipData implements Parcelable {
} else {
mIcon = null;
}
+ mItems = new ArrayList<Item>();
final int N = in.readInt();
for (int i=0; i<N; i++) {
CharSequence text = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
diff --git a/core/java/android/content/ClipDescription.java b/core/java/android/content/ClipDescription.java
index b5fa20cda7ff..c6b51efbc362 100644
--- a/core/java/android/content/ClipDescription.java
+++ b/core/java/android/content/ClipDescription.java
@@ -184,6 +184,39 @@ public class ClipDescription implements Parcelable {
}
@Override
+ public String toString() {
+ StringBuilder b = new StringBuilder(128);
+
+ b.append("ClipDescription { ");
+ toShortString(b);
+ b.append(" }");
+
+ return b.toString();
+ }
+
+ /** @hide */
+ public boolean toShortString(StringBuilder b) {
+ boolean first = true;
+ for (int i=0; i<mMimeTypes.length; i++) {
+ if (!first) {
+ b.append(' ');
+ }
+ first = false;
+ b.append(mMimeTypes[i]);
+ }
+ if (mLabel != null) {
+ if (!first) {
+ b.append(' ');
+ }
+ first = false;
+ b.append('"');
+ b.append(mLabel);
+ b.append('"');
+ }
+ return !first;
+ }
+
+ @Override
public int describeContents() {
return 0;
}
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index b1b09d56c363..57391199a31a 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -2688,12 +2688,20 @@ public class Intent implements Parcelable, Cloneable {
/**
* If set, the recipient of this Intent will be granted permission to
- * perform read operations on the Uri in the Intent's data.
+ * perform read operations on the Uri in the Intent's data and any URIs
+ * specified in its ClipData. When applying to an Intent's ClipData,
+ * all URIs as well as recursive traversals through data or other ClipData
+ * in Intent items will be granted; only the grant flags of the top-level
+ * Intent are used.
*/
public static final int FLAG_GRANT_READ_URI_PERMISSION = 0x00000001;
/**
* If set, the recipient of this Intent will be granted permission to
- * perform write operations on the Uri in the Intent's data.
+ * perform write operations on the Uri in the Intent's data and any URIs
+ * specified in its ClipData. When applying to an Intent's ClipData,
+ * all URIs as well as recursive traversals through data or other ClipData
+ * in Intent items will be granted; only the grant flags of the top-level
+ * Intent are used.
*/
public static final int FLAG_GRANT_WRITE_URI_PERMISSION = 0x00000002;
/**
@@ -3018,6 +3026,7 @@ public class Intent implements Parcelable, Cloneable {
private Bundle mExtras;
private Rect mSourceBounds;
private Intent mSelector;
+ private ClipData mClipData;
// ---------------------------------------------------------------------
@@ -3049,6 +3058,9 @@ public class Intent implements Parcelable, Cloneable {
if (o.mSelector != null) {
this.mSelector = new Intent(o.mSelector);
}
+ if (o.mClipData != null) {
+ this.mClipData = new ClipData(o.mClipData);
+ }
}
@Override
@@ -3729,6 +3741,16 @@ public class Intent implements Parcelable, Cloneable {
}
/**
+ * Return the {@link ClipData} associated with this Intent. If there is
+ * none, returns null. See {@link #setClipData} for more information.
+ *
+ * @see #setClipData;
+ */
+ public ClipData getClipData() {
+ return mClipData;
+ }
+
+ /**
* Sets the ClassLoader that will be used when unmarshalling
* any Parcelable values from the extras of this Intent.
*
@@ -4683,6 +4705,37 @@ public class Intent implements Parcelable, Cloneable {
}
/**
+ * Set a {@link ClipData} associated with this Intent. This replaces any
+ * previously set ClipData.
+ *
+ * <p>The ClipData in an intent is not used for Intent matching or other
+ * such operations. Semantically it is like extras, used to transmit
+ * additional data with the Intent. The main feature of using this over
+ * the extras for data is that {@link #FLAG_GRANT_READ_URI_PERMISSION}
+ * and {@link #FLAG_GRANT_WRITE_URI_PERMISSION} will operate on any URI
+ * items included in the clip data. This is useful, in particular, if
+ * you want to transmit an Intent containing multiple <code>content:</code>
+ * URIs for which the recipient may not have global permission to access the
+ * content provider.
+ *
+ * <p>If the ClipData contains items that are themselves Intents, any
+ * grant flags in those Intents will be ignored. Only the top-level flags
+ * of the main Intent are respected, and will be applied to all Uri or
+ * Intent items in the clip (or sub-items of the clip).
+ *
+ * <p>The MIME type, label, and icon in the ClipData object are not
+ * directly used by Intent. Applications should generally rely on the
+ * MIME type of the Intent itself, not what it may find in the ClipData.
+ * A common practice is to construct a ClipData for use with an Intent
+ * with a MIME type of "*\/*".
+ *
+ * @param clip The new clip to set. May be null to clear the current clip.
+ */
+ public void setClipData(ClipData clip) {
+ mClipData = clip;
+ }
+
+ /**
* Add extended data to the intent. The name must include a package
* prefix, for example the app com.android.contacts would use names
* like "com.android.contacts.ShowAll".
@@ -5660,6 +5713,12 @@ public class Intent implements Parcelable, Cloneable {
public static final int FILL_IN_SELECTOR = 1<<6;
/**
+ * Use with {@link #fillIn} to allow the current ClipData to be
+ * overwritten, even if it is already set.
+ */
+ public static final int FILL_IN_CLIP_DATA = 1<<7;
+
+ /**
* Copy the contents of <var>other</var> in to this object, but only
* where fields are not defined by this object. For purposes of a field
* being defined, the following pieces of data in the Intent are
@@ -5673,19 +5732,22 @@ public class Intent implements Parcelable, Cloneable {
* <li> package, as set by {@link #setPackage}.
* <li> component, as set by {@link #setComponent(ComponentName)} or
* related methods.
- * <li> source bounds, as set by {@link #setSourceBounds}
+ * <li> source bounds, as set by {@link #setSourceBounds}.
+ * <li> selector, as set by {@link #setSelector(Intent)}.
+ * <li> clip data, as set by {@link #setClipData(ClipData)}.
* <li> each top-level name in the associated extras.
* </ul>
*
* <p>In addition, you can use the {@link #FILL_IN_ACTION},
* {@link #FILL_IN_DATA}, {@link #FILL_IN_CATEGORIES}, {@link #FILL_IN_PACKAGE},
- * {@link #FILL_IN_COMPONENT}, {@link #FILL_IN_SOURCE_BOUNDS}, and
- * {@link #FILL_IN_SELECTOR} to override the restriction where the
- * corresponding field will not be replaced if it is already set.
+ * {@link #FILL_IN_COMPONENT}, {@link #FILL_IN_SOURCE_BOUNDS},
+ * {@link #FILL_IN_SELECTOR}, and {@link #FILL_IN_CLIP_DATA} to override
+ * the restriction where the corresponding field will not be replaced if
+ * it is already set.
*
- * <p>Note: The component field will only be copied if {@link #FILL_IN_COMPONENT} is explicitly
- * specified. The selector will only be copied if {@link #FILL_IN_SELECTOR} is
- * explicitly specified.
+ * <p>Note: The component field will only be copied if {@link #FILL_IN_COMPONENT}
+ * is explicitly specified. The selector will only be copied if
+ * {@link #FILL_IN_SELECTOR} is explicitly specified.
*
* <p>For example, consider Intent A with {data="foo", categories="bar"}
* and Intent B with {action="gotit", data-type="some/thing",
@@ -5742,6 +5804,11 @@ public class Intent implements Parcelable, Cloneable {
changes |= FILL_IN_SELECTOR;
}
}
+ if (other.mClipData != null
+ && (mClipData == null || (flags&FILL_IN_CLIP_DATA) != 0)) {
+ mClipData = other.mClipData;
+ changes |= FILL_IN_CLIP_DATA;
+ }
// Component is special: it can -only- be set if explicitly allowed,
// since otherwise the sender could force the intent somewhere the
// originator didn't intend.
@@ -5938,7 +6005,7 @@ public class Intent implements Parcelable, Cloneable {
StringBuilder b = new StringBuilder(128);
b.append("Intent { ");
- toShortString(b, true, true, true);
+ toShortString(b, true, true, true, false);
b.append(" }");
return b.toString();
@@ -5949,21 +6016,33 @@ public class Intent implements Parcelable, Cloneable {
StringBuilder b = new StringBuilder(128);
b.append("Intent { ");
- toShortString(b, false, true, true);
+ toShortString(b, false, true, true, false);
+ b.append(" }");
+
+ return b.toString();
+ }
+
+ /** @hide */
+ public String toInsecureStringWithClip() {
+ StringBuilder b = new StringBuilder(128);
+
+ b.append("Intent { ");
+ toShortString(b, false, true, true, true);
b.append(" }");
return b.toString();
}
/** @hide */
- public String toShortString(boolean secure, boolean comp, boolean extras) {
+ public String toShortString(boolean secure, boolean comp, boolean extras, boolean clip) {
StringBuilder b = new StringBuilder(128);
- toShortString(b, secure, comp, extras);
+ toShortString(b, secure, comp, extras, clip);
return b.toString();
}
/** @hide */
- public void toShortString(StringBuilder b, boolean secure, boolean comp, boolean extras) {
+ public void toShortString(StringBuilder b, boolean secure, boolean comp, boolean extras,
+ boolean clip) {
boolean first = true;
if (mAction != null) {
b.append("act=").append(mAction);
@@ -6031,6 +6110,19 @@ public class Intent implements Parcelable, Cloneable {
first = false;
b.append("bnds=").append(mSourceBounds.toShortString());
}
+ if (mClipData != null) {
+ if (!first) {
+ b.append(' ');
+ }
+ first = false;
+ if (clip) {
+ b.append("clip={");
+ mClipData.toShortString(b);
+ b.append('}');
+ } else {
+ b.append("(has clip)");
+ }
+ }
if (extras && mExtras != null) {
if (!first) {
b.append(' ');
@@ -6040,7 +6132,7 @@ public class Intent implements Parcelable, Cloneable {
}
if (mSelector != null) {
b.append(" sel={");
- mSelector.toShortString(b, secure, comp, extras);
+ mSelector.toShortString(b, secure, comp, extras, clip);
b.append("}");
}
}
@@ -6209,6 +6301,13 @@ public class Intent implements Parcelable, Cloneable {
out.writeInt(0);
}
+ if (mClipData != null) {
+ out.writeInt(1);
+ mClipData.writeToParcel(out, flags);
+ } else {
+ out.writeInt(0);
+ }
+
out.writeBundle(mExtras);
}
@@ -6254,6 +6353,10 @@ public class Intent implements Parcelable, Cloneable {
mSelector = new Intent(in);
}
+ if (in.readInt() != 0) {
+ mClipData = new ClipData(in);
+ }
+
mExtras = in.readBundle();
}
diff --git a/services/java/com/android/server/AlarmManagerService.java b/services/java/com/android/server/AlarmManagerService.java
index b8c44d9cf99a..057440572384 100644
--- a/services/java/com/android/server/AlarmManagerService.java
+++ b/services/java/com/android/server/AlarmManagerService.java
@@ -477,7 +477,8 @@ class AlarmManagerService extends IAlarmManager.Stub {
: bs.filterStats.entrySet()) {
pw.print(" "); pw.print(fe.getValue().count);
pw.print(" alarms: ");
- pw.println(fe.getKey().getIntent().toShortString(false, true, false));
+ pw.println(fe.getKey().getIntent().toShortString(
+ false, true, false, true));
}
}
}
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 4ea2f041c74d..ce597adf5c5b 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -49,10 +49,10 @@ import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
-import android.app.WallpaperManager;
import android.app.backup.IBackupManager;
import android.content.ActivityNotFoundException;
import android.content.BroadcastReceiver;
+import android.content.ClipData;
import android.content.ComponentCallbacks2;
import android.content.ComponentName;
import android.content.ContentResolver;
@@ -4657,9 +4657,11 @@ public final class ActivityManagerService extends ActivityManagerNative
* if callingUid is not allowed to do this. Returns the uid of the target
* if the URI permission grant should be performed; returns -1 if it is not
* needed (for example targetPkg already has permission to access the URI).
+ * If you already know the uid of the target, you can supply it in
+ * lastTargetUid else set that to -1.
*/
int checkGrantUriPermissionLocked(int callingUid, String targetPkg,
- Uri uri, int modeFlags) {
+ Uri uri, int modeFlags, int lastTargetUid) {
modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
| Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
if (modeFlags == 0) {
@@ -4698,8 +4700,8 @@ public final class ActivityManagerService extends ActivityManagerNative
return -1;
}
- int targetUid;
- if (targetPkg != null) {
+ int targetUid = lastTargetUid;
+ if (targetUid < 0 && targetPkg != null) {
try {
targetUid = pm.getPackageUid(targetPkg);
if (targetUid < 0) {
@@ -4710,8 +4712,6 @@ public final class ActivityManagerService extends ActivityManagerNative
} catch (RemoteException ex) {
return -1;
}
- } else {
- targetUid = -1;
}
if (targetUid >= 0) {
@@ -4783,7 +4783,7 @@ public final class ActivityManagerService extends ActivityManagerNative
Uri uri, int modeFlags) {
enforceNotIsolatedCaller("checkGrantUriPermission");
synchronized(this) {
- return checkGrantUriPermissionLocked(callingUid, targetPkg, uri, modeFlags);
+ return checkGrantUriPermissionLocked(callingUid, targetPkg, uri, modeFlags, -1);
}
}
@@ -4830,13 +4830,13 @@ public final class ActivityManagerService extends ActivityManagerNative
}
}
- void grantUriPermissionLocked(int callingUid,
- String targetPkg, Uri uri, int modeFlags, UriPermissionOwner owner) {
+ void grantUriPermissionLocked(int callingUid, String targetPkg, Uri uri,
+ int modeFlags, UriPermissionOwner owner) {
if (targetPkg == null) {
throw new NullPointerException("targetPkg");
}
- int targetUid = checkGrantUriPermissionLocked(callingUid, targetPkg, uri, modeFlags);
+ int targetUid = checkGrantUriPermissionLocked(callingUid, targetPkg, uri, modeFlags, -1);
if (targetUid < 0) {
return;
}
@@ -4844,13 +4844,26 @@ public final class ActivityManagerService extends ActivityManagerNative
grantUriPermissionUncheckedLocked(targetUid, targetPkg, uri, modeFlags, owner);
}
+ static class NeededUriGrants extends ArrayList<Uri> {
+ final String targetPkg;
+ final int targetUid;
+ final int flags;
+
+ NeededUriGrants(String _targetPkg, int _targetUid, int _flags) {
+ targetPkg = _targetPkg;
+ targetUid = _targetUid;
+ flags = _flags;
+ }
+ }
+
/**
* Like checkGrantUriPermissionLocked, but takes an Intent.
*/
- int checkGrantUriPermissionFromIntentLocked(int callingUid,
- String targetPkg, Intent intent) {
+ NeededUriGrants checkGrantUriPermissionFromIntentLocked(int callingUid,
+ String targetPkg, Intent intent, int mode, NeededUriGrants needed) {
if (DEBUG_URI_PERMISSION) Slog.v(TAG,
- "Checking URI perm to " + (intent != null ? intent.getData() : null)
+ "Checking URI perm to data=" + (intent != null ? intent.getData() : null)
+ + " clip=" + (intent != null ? intent.getClipData() : null)
+ " from " + intent + "; flags=0x"
+ Integer.toHexString(intent != null ? intent.getFlags() : 0));
@@ -4859,33 +4872,74 @@ public final class ActivityManagerService extends ActivityManagerNative
}
if (intent == null) {
- return -1;
+ return null;
}
Uri data = intent.getData();
- if (data == null) {
- return -1;
+ ClipData clip = intent.getClipData();
+ if (data == null && clip == null) {
+ return null;
+ }
+ if (data != null) {
+ int target = checkGrantUriPermissionLocked(callingUid, targetPkg, data,
+ mode, needed != null ? needed.targetUid : -1);
+ if (target > 0) {
+ if (needed == null) {
+ needed = new NeededUriGrants(targetPkg, target, mode);
+ }
+ needed.add(data);
+ }
+ }
+ if (clip != null) {
+ for (int i=0; i<clip.getItemCount(); i++) {
+ Uri uri = clip.getItemAt(i).getUri();
+ if (uri != null) {
+ int target = -1;
+ target = checkGrantUriPermissionLocked(callingUid, targetPkg, uri,
+ mode, needed != null ? needed.targetUid : -1);
+ if (target > 0) {
+ if (needed == null) {
+ needed = new NeededUriGrants(targetPkg, target, mode);
+ }
+ needed.add(uri);
+ }
+ } else {
+ Intent clipIntent = clip.getItemAt(i).getIntent();
+ if (clipIntent != null) {
+ NeededUriGrants newNeeded = checkGrantUriPermissionFromIntentLocked(
+ callingUid, targetPkg, clipIntent, mode, needed);
+ if (newNeeded != null) {
+ needed = newNeeded;
+ }
+ }
+ }
+ }
}
- return checkGrantUriPermissionLocked(callingUid, targetPkg, data,
- intent.getFlags());
+
+ return needed;
}
/**
* Like grantUriPermissionUncheckedLocked, but takes an Intent.
*/
- void grantUriPermissionUncheckedFromIntentLocked(int targetUid,
- String targetPkg, Intent intent, UriPermissionOwner owner) {
- grantUriPermissionUncheckedLocked(targetUid, targetPkg, intent.getData(),
- intent.getFlags(), owner);
+ void grantUriPermissionUncheckedFromIntentLocked(NeededUriGrants needed,
+ UriPermissionOwner owner) {
+ if (needed != null) {
+ for (int i=0; i<needed.size(); i++) {
+ grantUriPermissionUncheckedLocked(needed.targetUid, needed.targetPkg,
+ needed.get(i), needed.flags, owner);
+ }
+ }
}
void grantUriPermissionFromIntentLocked(int callingUid,
String targetPkg, Intent intent, UriPermissionOwner owner) {
- int targetUid = checkGrantUriPermissionFromIntentLocked(callingUid, targetPkg, intent);
- if (targetUid < 0) {
+ NeededUriGrants needed = checkGrantUriPermissionFromIntentLocked(callingUid, targetPkg,
+ intent, intent.getFlags(), null);
+ if (needed == null) {
return;
}
- grantUriPermissionUncheckedFromIntentLocked(targetUid, targetPkg, intent, owner);
+ grantUriPermissionUncheckedFromIntentLocked(needed, owner);
}
public void grantUriPermission(IApplicationThread caller, String targetPkg,
@@ -5406,7 +5460,7 @@ public final class ActivityManagerService extends ActivityManagerNative
stopServiceLocked(sr);
} else {
sr.pendingStarts.add(new ServiceRecord.StartItem(sr, true,
- sr.makeNextStartId(), baseIntent, -1));
+ sr.makeNextStartId(), baseIntent, null));
if (sr.app != null && sr.app.thread != null) {
sendServiceArgsLocked(sr, false);
}
@@ -9044,7 +9098,7 @@ public final class ActivityManagerService extends ActivityManagerNative
for (int i=0; i<N; i++) {
sb.setLength(0);
sb.append(" Intent: ");
- intents.get(i).toShortString(sb, false, true, false);
+ intents.get(i).toShortString(sb, false, true, false, false);
pw.println(sb.toString());
Bundle bundle = intents.get(i).getExtras();
if (bundle != null) {
@@ -9129,7 +9183,7 @@ public final class ActivityManagerService extends ActivityManagerNative
ConnectionRecord conn = clist.get(i);
pw.print(" ");
pw.print(conn.binding.intent.intent.getIntent()
- .toShortString(false, false, false));
+ .toShortString(false, false, false, false));
pw.print(" -> ");
ProcessRecord proc = conn.binding.client;
pw.println(proc != null ? proc.toShortString() : "null");
@@ -9380,7 +9434,7 @@ public final class ActivityManagerService extends ActivityManagerNative
// Complete + brief == give a summary. Isn't that obvious?!?
if (lastTask.intent != null) {
pw.print(prefix); pw.print(" ");
- pw.println(lastTask.intent.toInsecureString());
+ pw.println(lastTask.intent.toInsecureStringWithClip());
}
}
}
@@ -10692,9 +10746,9 @@ public final class ActivityManagerService extends ActivityManagerNative
si.deliveredTime = SystemClock.uptimeMillis();
r.deliveredStarts.add(si);
si.deliveryCount++;
- if (si.targetPermissionUid >= 0 && si.intent != null) {
- grantUriPermissionUncheckedFromIntentLocked(si.targetPermissionUid,
- r.packageName, si.intent, si.getUriPermissionsLocked());
+ if (si.neededGrants != null) {
+ grantUriPermissionUncheckedFromIntentLocked(si.neededGrants,
+ si.getUriPermissionsLocked());
}
bumpServiceExecutingLocked(r, "start");
if (!oomAdjusted) {
@@ -10772,7 +10826,7 @@ public final class ActivityManagerService extends ActivityManagerNative
boolean created = false;
try {
mStringBuilder.setLength(0);
- r.intent.getIntent().toShortString(mStringBuilder, true, false, true);
+ r.intent.getIntent().toShortString(mStringBuilder, true, false, true, false);
EventLog.writeEvent(EventLogTags.AM_CREATE_SERVICE,
System.identityHashCode(r), r.shortName,
mStringBuilder.toString(), r.app.pid);
@@ -10798,7 +10852,7 @@ public final class ActivityManagerService extends ActivityManagerNative
// be called.
if (r.startRequested && r.callStart && r.pendingStarts.size() == 0) {
r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
- null, -1));
+ null, null));
}
sendServiceArgsLocked(r, true);
@@ -11170,15 +11224,15 @@ public final class ActivityManagerService extends ActivityManagerNative
? res.permission : "private to package");
}
ServiceRecord r = res.record;
- int targetPermissionUid = checkGrantUriPermissionFromIntentLocked(
- callingUid, r.packageName, service);
+ NeededUriGrants neededGrants = checkGrantUriPermissionFromIntentLocked(
+ callingUid, r.packageName, service, service.getFlags(), null);
if (unscheduleServiceRestartLocked(r)) {
if (DEBUG_SERVICE) Slog.v(TAG, "START SERVICE WHILE RESTART PENDING: " + r);
}
r.startRequested = true;
r.callStart = false;
r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
- service, targetPermissionUid));
+ service, neededGrants));
r.lastActivity = SystemClock.uptimeMillis();
synchronized (r.stats.getBatteryStats()) {
r.stats.startRunningLocked();
diff --git a/services/java/com/android/server/am/ActivityRecord.java b/services/java/com/android/server/am/ActivityRecord.java
index cdab6c6f67b3..a337b400288a 100644
--- a/services/java/com/android/server/am/ActivityRecord.java
+++ b/services/java/com/android/server/am/ActivityRecord.java
@@ -127,26 +127,27 @@ final class ActivityRecord {
pw.print(prefix); pw.print("packageName="); pw.print(packageName);
pw.print(" processName="); pw.println(processName);
pw.print(prefix); pw.print("launchedFromUid="); pw.print(launchedFromUid);
- pw.print(prefix); pw.print("userId="); pw.print(userId);
- pw.print(" app="); pw.println(app);
- pw.print(prefix); pw.println(intent.toInsecureString());
+ pw.print(" userId="); pw.println(userId);
+ pw.print(prefix); pw.print("app="); pw.println(app);
+ pw.print(prefix); pw.println(intent.toInsecureStringWithClip());
pw.print(prefix); pw.print("frontOfTask="); pw.print(frontOfTask);
pw.print(" task="); pw.println(task);
pw.print(prefix); pw.print("taskAffinity="); pw.println(taskAffinity);
pw.print(prefix); pw.print("realActivity=");
pw.println(realActivity.flattenToShortString());
- pw.print(prefix); pw.print("base="); pw.print(baseDir);
- if (!resDir.equals(baseDir)) pw.print(" res="); pw.print(resDir);
- pw.print(" data="); pw.println(dataDir);
- pw.print(prefix); pw.print("labelRes=0x");
- pw.print(Integer.toHexString(labelRes));
- pw.print(" icon=0x"); pw.print(Integer.toHexString(icon));
- pw.print(" theme=0x"); pw.println(Integer.toHexString(theme));
+ pw.print(prefix); pw.print("baseDir="); pw.println(baseDir);
+ if (!resDir.equals(baseDir)) {
+ pw.print(prefix); pw.print("resDir="); pw.println(resDir);
+ }
+ pw.print(prefix); pw.print("dataDir="); pw.println(dataDir);
pw.print(prefix); pw.print("stateNotNeeded="); pw.print(stateNotNeeded);
pw.print(" componentSpecified="); pw.print(componentSpecified);
pw.print(" isHomeActivity="); pw.println(isHomeActivity);
+ pw.print(prefix); pw.print("compat="); pw.print(compat);
+ pw.print(" labelRes=0x"); pw.print(Integer.toHexString(labelRes));
+ pw.print(" icon=0x"); pw.print(Integer.toHexString(icon));
+ pw.print(" theme=0x"); pw.println(Integer.toHexString(theme));
pw.print(prefix); pw.print("config="); pw.println(configuration);
- pw.print(prefix); pw.print("compat="); pw.println(compat);
if (resultTo != null || resultWho != null) {
pw.print(prefix); pw.print("resultTo="); pw.print(resultTo);
pw.print(" resultWho="); pw.print(resultWho);
@@ -193,13 +194,11 @@ final class ActivityRecord {
TimeUtils.formatDuration(launchTime, pw); pw.print(" startTime=");
TimeUtils.formatDuration(startTime, pw); pw.println("");
}
- if (lastVisibleTime != 0) {
- pw.print(prefix); pw.print("lastVisibleTime=");
- TimeUtils.formatDuration(lastVisibleTime, pw); pw.println("");
- }
- if (waitingVisible || nowVisible) {
+ if (lastVisibleTime != 0 || waitingVisible || nowVisible) {
pw.print(prefix); pw.print("waitingVisible="); pw.print(waitingVisible);
- pw.print(" nowVisible="); pw.println(nowVisible);
+ pw.print(" nowVisible="); pw.print(nowVisible);
+ pw.print("lastVisibleTime=");
+ TimeUtils.formatDuration(lastVisibleTime, pw); pw.println("");
}
if (configDestroy || configChangeFlags != 0) {
pw.print(prefix); pw.print("configDestroy="); pw.print(configDestroy);
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index f9641eb564f4..19fe1bfba801 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -2290,8 +2290,8 @@ final class ActivityStack {
}
if (err == START_SUCCESS) {
- Slog.i(TAG, "START {" + intent.toShortString(true, true, true) + "} from pid "
- + (callerApp != null ? callerApp.pid : callingPid));
+ Slog.i(TAG, "START {" + intent.toShortString(true, true, true, false)
+ + "} from pid " + (callerApp != null ? callerApp.pid : callingPid));
}
ActivityRecord sourceRecord = null;
diff --git a/services/java/com/android/server/am/IntentBindRecord.java b/services/java/com/android/server/am/IntentBindRecord.java
index 2618c77e2b2d..c94f714fdbaa 100644
--- a/services/java/com/android/server/am/IntentBindRecord.java
+++ b/services/java/com/android/server/am/IntentBindRecord.java
@@ -54,7 +54,7 @@ class IntentBindRecord {
void dumpInService(PrintWriter pw, String prefix) {
pw.print(prefix); pw.print("intent={");
- pw.print(intent.getIntent().toShortString(false, true, false));
+ pw.print(intent.getIntent().toShortString(false, true, false, false));
pw.println('}');
pw.print(prefix); pw.print("binder="); pw.println(binder);
pw.print(prefix); pw.print("requested="); pw.print(requested);
@@ -89,7 +89,7 @@ class IntentBindRecord {
sb.append(service.shortName);
sb.append(':');
if (intent != null) {
- intent.getIntent().toShortString(sb, false, false, false);
+ intent.getIntent().toShortString(sb, false, false, false, false);
}
sb.append('}');
return stringName = sb.toString();
diff --git a/services/java/com/android/server/am/PendingIntentRecord.java b/services/java/com/android/server/am/PendingIntentRecord.java
index 3b6a97c41ecc..0043874e18e6 100644
--- a/services/java/com/android/server/am/PendingIntentRecord.java
+++ b/services/java/com/android/server/am/PendingIntentRecord.java
@@ -152,7 +152,7 @@ class PendingIntentRecord extends IIntentSender.Stub {
return "Key{" + typeName() + " pkg=" + packageName
+ " intent="
+ (requestIntent != null
- ? requestIntent.toShortString(false, true, false) : "<null>")
+ ? requestIntent.toShortString(false, true, false, false) : "<null>")
+ " flags=0x" + Integer.toHexString(flags) + "}";
}
@@ -320,7 +320,7 @@ class PendingIntentRecord extends IIntentSender.Stub {
}
if (key.requestIntent != null) {
pw.print(prefix); pw.print("requestIntent=");
- pw.println(key.requestIntent.toShortString(false, true, true));
+ pw.println(key.requestIntent.toShortString(false, true, true, true));
}
if (sent || canceled) {
pw.print(prefix); pw.print("sent="); pw.print(sent);
diff --git a/services/java/com/android/server/am/ServiceRecord.java b/services/java/com/android/server/am/ServiceRecord.java
index daa3653d0bc2..828eef767f44 100644
--- a/services/java/com/android/server/am/ServiceRecord.java
+++ b/services/java/com/android/server/am/ServiceRecord.java
@@ -106,7 +106,7 @@ class ServiceRecord extends Binder {
final boolean taskRemoved;
final int id;
final Intent intent;
- final int targetPermissionUid;
+ final ActivityManagerService.NeededUriGrants neededGrants;
long deliveredTime;
int deliveryCount;
int doneExecutingCount;
@@ -115,12 +115,12 @@ class ServiceRecord extends Binder {
String stringName; // caching of toString
StartItem(ServiceRecord _sr, boolean _taskRemoved, int _id, Intent _intent,
- int _targetPermissionUid) {
+ ActivityManagerService.NeededUriGrants _neededGrants) {
sr = _sr;
taskRemoved = _taskRemoved;
id = _id;
intent = _intent;
- targetPermissionUid = _targetPermissionUid;
+ neededGrants = _neededGrants;
}
UriPermissionOwner getUriPermissionsLocked() {
@@ -177,9 +177,9 @@ class ServiceRecord extends Binder {
pw.print(prefix); pw.print(" intent=");
if (si.intent != null) pw.println(si.intent.toString());
else pw.println("null");
- if (si.targetPermissionUid >= 0) {
- pw.print(prefix); pw.print(" targetPermissionUid=");
- pw.println(si.targetPermissionUid);
+ if (si.neededGrants != null) {
+ pw.print(prefix); pw.print(" neededGrants=");
+ pw.println(si.neededGrants);
}
if (si.uriPermissions != null) {
if (si.uriPermissions.readUriPermissions != null) {
@@ -196,7 +196,7 @@ class ServiceRecord extends Binder {
void dump(PrintWriter pw, String prefix) {
pw.print(prefix); pw.print("intent={");
- pw.print(intent.getIntent().toShortString(false, true, false));
+ pw.print(intent.getIntent().toShortString(false, true, false, true));
pw.println('}');
pw.print(prefix); pw.print("packageName="); pw.println(packageName);
pw.print(prefix); pw.print("processName="); pw.println(processName);
diff --git a/services/java/com/android/server/am/TaskRecord.java b/services/java/com/android/server/am/TaskRecord.java
index 47ec21805638..67873ccefdcb 100644
--- a/services/java/com/android/server/am/TaskRecord.java
+++ b/services/java/com/android/server/am/TaskRecord.java
@@ -111,14 +111,14 @@ class TaskRecord extends ThumbnailHolder {
if (intent != null) {
StringBuilder sb = new StringBuilder(128);
sb.append(prefix); sb.append("intent={");
- intent.toShortString(sb, false, true, false);
+ intent.toShortString(sb, false, true, false, true);
sb.append('}');
pw.println(sb.toString());
}
if (affinityIntent != null) {
StringBuilder sb = new StringBuilder(128);
sb.append(prefix); sb.append("affinityIntent={");
- affinityIntent.toShortString(sb, false, true, false);
+ affinityIntent.toShortString(sb, false, true, false, true);
sb.append('}');
pw.println(sb.toString());
}