am 39792d22: Fix bugs with granting permissions through onNewIntent().

Merge commit '39792d2262352ae775091876d5488d2412a2ff92' into gingerbread-plus-aosp

* commit '39792d2262352ae775091876d5488d2412a2ff92':
  Fix bugs with granting permissions through onNewIntent().
This commit is contained in:
Dianne Hackborn
2010-08-20 11:53:29 -07:00
committed by Android Git Automerger
7 changed files with 357 additions and 156 deletions

View File

@ -389,15 +389,17 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
if (permission != null) { if (permission != null) {
pw.println(prefix + "permission=" + permission); pw.println(prefix + "permission=" + permission);
} }
pw.println(prefix + "uid=" + uid + " taskAffinity=" + taskAffinity); pw.println(prefix + "processName=" + processName);
if (theme != 0) { pw.println(prefix + "taskAffinity=" + taskAffinity);
pw.println(prefix + "theme=0x" + Integer.toHexString(theme)); pw.println(prefix + "uid=" + uid + " flags=0x" + Integer.toHexString(flags)
} + " theme=0x" + Integer.toHexString(theme));
pw.println(prefix + "flags=0x" + Integer.toHexString(flags)
+ " processName=" + processName);
pw.println(prefix + "sourceDir=" + sourceDir); pw.println(prefix + "sourceDir=" + sourceDir);
if (!sourceDir.equals(publicSourceDir)) {
pw.println(prefix + "publicSourceDir=" + publicSourceDir); pw.println(prefix + "publicSourceDir=" + publicSourceDir);
}
if (resourceDirs != null) {
pw.println(prefix + "resourceDirs=" + resourceDirs); pw.println(prefix + "resourceDirs=" + resourceDirs);
}
pw.println(prefix + "dataDir=" + dataDir); pw.println(prefix + "dataDir=" + dataDir);
if (sharedLibraryFiles != null) { if (sharedLibraryFiles != null) {
pw.println(prefix + "sharedLibraryFiles=" + sharedLibraryFiles); pw.println(prefix + "sharedLibraryFiles=" + sharedLibraryFiles);

View File

@ -4096,16 +4096,23 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
} }
} }
void grantUriPermissionLocked(int callingUid, /**
String targetPkg, Uri uri, int modeFlags, ActivityRecord activity) { * Check if the targetPkg can be granted permission to access uri by
* the callingUid using the given modeFlags. Throws a security exception
* 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).
*/
int checkGrantUriPermissionLocked(int callingUid, String targetPkg,
Uri uri, int modeFlags) {
modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
| Intent.FLAG_GRANT_WRITE_URI_PERMISSION); | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
if (modeFlags == 0) { if (modeFlags == 0) {
return; return -1;
} }
if (DEBUG_URI_PERMISSION) Slog.v(TAG, if (DEBUG_URI_PERMISSION) Slog.v(TAG,
"Requested grant " + targetPkg + " permission to " + uri); "Checking grant " + targetPkg + " permission to " + uri);
final IPackageManager pm = AppGlobals.getPackageManager(); final IPackageManager pm = AppGlobals.getPackageManager();
@ -4113,7 +4120,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
if (!ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) { if (!ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
if (DEBUG_URI_PERMISSION) Slog.v(TAG, if (DEBUG_URI_PERMISSION) Slog.v(TAG,
"Can't grant URI permission for non-content URI: " + uri); "Can't grant URI permission for non-content URI: " + uri);
return; return -1;
} }
String name = uri.getAuthority(); String name = uri.getAuthority();
@ -4130,7 +4137,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
} }
if (pi == null) { if (pi == null) {
Slog.w(TAG, "No content provider found for: " + name); Slog.w(TAG, "No content provider found for: " + name);
return; return -1;
} }
int targetUid; int targetUid;
@ -4139,10 +4146,10 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
if (targetUid < 0) { if (targetUid < 0) {
if (DEBUG_URI_PERMISSION) Slog.v(TAG, if (DEBUG_URI_PERMISSION) Slog.v(TAG,
"Can't grant URI permission no uid for: " + targetPkg); "Can't grant URI permission no uid for: " + targetPkg);
return; return -1;
} }
} catch (RemoteException ex) { } catch (RemoteException ex) {
return; return -1;
} }
// First... does the target actually need this permission? // First... does the target actually need this permission?
@ -4150,7 +4157,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// No need to grant the target this permission. // No need to grant the target this permission.
if (DEBUG_URI_PERMISSION) Slog.v(TAG, if (DEBUG_URI_PERMISSION) Slog.v(TAG,
"Target " + targetPkg + " already has full permission to " + uri); "Target " + targetPkg + " already has full permission to " + uri);
return; return -1;
} }
// Second... is the provider allowing granting of URI permissions? // Second... is the provider allowing granting of URI permissions?
@ -4187,12 +4194,23 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
} }
} }
// Okay! So here we are: the caller has the assumed permission return targetUid;
}
void grantUriPermissionUncheckedLocked(int targetUid, String targetPkg,
Uri uri, int modeFlags, UriPermissionOwner owner) {
modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
| Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
if (modeFlags == 0) {
return;
}
// So here we are: the caller has the assumed permission
// to the uri, and the target doesn't. Let's now give this to // to the uri, and the target doesn't. Let's now give this to
// the target. // the target.
if (DEBUG_URI_PERMISSION) Slog.v(TAG, if (DEBUG_URI_PERMISSION) Slog.v(TAG,
"Granting " + targetPkg + " permission to " + uri); "Granting " + targetPkg + "/" + targetUid + " permission to " + uri);
HashMap<Uri, UriPermission> targetUris HashMap<Uri, UriPermission> targetUris
= mGrantedUriPermissions.get(targetUid); = mGrantedUriPermissions.get(targetUid);
@ -4208,39 +4226,65 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
} }
perm.modeFlags |= modeFlags; perm.modeFlags |= modeFlags;
if (activity == null) { if (owner == null) {
perm.globalModeFlags |= modeFlags; perm.globalModeFlags |= modeFlags;
} else if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) { } else if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
perm.readActivities.add(activity); perm.readOwners.add(owner);
if (activity.readUriPermissions == null) { owner.addReadPermission(perm);
activity.readUriPermissions = new HashSet<UriPermission>();
}
activity.readUriPermissions.add(perm);
} else if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) { } else if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
perm.writeActivities.add(activity); perm.writeOwners.add(owner);
if (activity.writeUriPermissions == null) { owner.addWritePermission(perm);
activity.writeUriPermissions = new HashSet<UriPermission>();
}
activity.writeUriPermissions.add(perm);
} }
} }
void grantUriPermissionFromIntentLocked(int callingUid, void grantUriPermissionLocked(int callingUid,
String targetPkg, Intent intent, ActivityRecord activity) { String targetPkg, Uri uri, int modeFlags, UriPermissionOwner owner) {
int targetUid = checkGrantUriPermissionLocked(callingUid, targetPkg, uri, modeFlags);
if (targetUid < 0) {
return;
}
grantUriPermissionUncheckedLocked(targetUid, targetPkg, uri, modeFlags, owner);
}
/**
* Like checkGrantUriPermissionLocked, but takes an Intent.
*/
int checkGrantUriPermissionFromIntentLocked(int callingUid,
String targetPkg, Intent intent) {
if (DEBUG_URI_PERMISSION) Slog.v(TAG, if (DEBUG_URI_PERMISSION) Slog.v(TAG,
"Grant URI perm to " + (intent != null ? intent.getData() : null) "Checking URI perm to " + (intent != null ? intent.getData() : null)
+ " from " + intent + "; flags=0x" + " from " + intent + "; flags=0x"
+ Integer.toHexString(intent != null ? intent.getFlags() : 0)); + Integer.toHexString(intent != null ? intent.getFlags() : 0));
if (intent == null) { if (intent == null) {
return; return -1;
} }
Uri data = intent.getData(); Uri data = intent.getData();
if (data == null) { if (data == null) {
return -1;
}
return checkGrantUriPermissionLocked(callingUid, targetPkg, data,
intent.getFlags());
}
/**
* 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 grantUriPermissionFromIntentLocked(int callingUid,
String targetPkg, Intent intent, UriPermissionOwner owner) {
int targetUid = checkGrantUriPermissionFromIntentLocked(callingUid, targetPkg, intent);
if (targetUid < 0) {
return; return;
} }
grantUriPermissionLocked(callingUid, targetPkg, data,
intent.getFlags(), activity); grantUriPermissionUncheckedFromIntentLocked(targetUid, targetPkg, intent, owner);
} }
public void grantUriPermission(IApplicationThread caller, String targetPkg, public void grantUriPermission(IApplicationThread caller, String targetPkg,
@ -8211,18 +8255,23 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
return; return;
} }
int i = 0; while (r.pendingStarts.size() > 0) {
while (i < N) {
try { try {
ServiceRecord.StartItem si = r.pendingStarts.get(i); ServiceRecord.StartItem si = r.pendingStarts.remove(0);
if (DEBUG_SERVICE) Slog.v(TAG, "Sending arguments to service: " if (DEBUG_SERVICE) Slog.v(TAG, "Sending arguments to service: "
+ r.name + " " + r.intent + " args=" + si.intent); + r.name + " " + r.intent + " args=" + si.intent);
if (si.intent == null && N > 1) { if (si.intent == null) {
// If somehow we got a dummy start at the front, then // If somehow we got a dummy start at the front, then
// just drop it here. // just drop it here.
i++;
continue; continue;
} }
si.deliveredTime = SystemClock.uptimeMillis();
r.deliveredStarts.add(si);
si.deliveryCount++;
if (si.targetPermissionUid >= 0) {
grantUriPermissionUncheckedFromIntentLocked(si.targetPermissionUid,
r.packageName, si.intent, si);
}
bumpServiceExecutingLocked(r); bumpServiceExecutingLocked(r);
if (!oomAdjusted) { if (!oomAdjusted) {
oomAdjusted = true; oomAdjusted = true;
@ -8236,10 +8285,6 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
flags |= Service.START_FLAG_REDELIVERY; flags |= Service.START_FLAG_REDELIVERY;
} }
r.app.thread.scheduleServiceArgs(r, si.id, flags, si.intent); r.app.thread.scheduleServiceArgs(r, si.id, flags, si.intent);
si.deliveredTime = SystemClock.uptimeMillis();
r.deliveredStarts.add(si);
si.deliveryCount++;
i++;
} catch (RemoteException e) { } catch (RemoteException e) {
// Remote process gone... we'll let the normal cleanup take // Remote process gone... we'll let the normal cleanup take
// care of this. // care of this.
@ -8249,14 +8294,6 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
break; break;
} }
} }
if (i == N) {
r.pendingStarts.clear();
} else {
while (i > 0) {
i--;
r.pendingStarts.remove(i);
}
}
} }
private final boolean requestServiceBindingLocked(ServiceRecord r, private final boolean requestServiceBindingLocked(ServiceRecord r,
@ -8339,7 +8376,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
if (r.lastStartId < 1) { if (r.lastStartId < 1) {
r.lastStartId = 1; r.lastStartId = 1;
} }
r.pendingStarts.add(new ServiceRecord.StartItem(r.lastStartId, null)); r.pendingStarts.add(new ServiceRecord.StartItem(r, r.lastStartId, null, -1));
} }
sendServiceArgsLocked(r, true); sendServiceArgsLocked(r, true);
@ -8359,6 +8396,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
if (N > 0) { if (N > 0) {
for (int i=N-1; i>=0; i--) { for (int i=N-1; i>=0; i--) {
ServiceRecord.StartItem si = r.deliveredStarts.get(i); ServiceRecord.StartItem si = r.deliveredStarts.get(i);
si.removeUriPermissionsLocked();
if (si.intent == null) { if (si.intent == null) {
// We'll generate this again if needed. // We'll generate this again if needed.
} else if (!allowCancel || (si.deliveryCount < ServiceRecord.MAX_DELIVERY_COUNT } else if (!allowCancel || (si.deliveryCount < ServiceRecord.MAX_DELIVERY_COUNT
@ -8598,7 +8636,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
r.foregroundNoti = null; r.foregroundNoti = null;
// Clear start entries. // Clear start entries.
r.deliveredStarts.clear(); r.clearDeliveredStartsLocked();
r.pendingStarts.clear(); r.pendingStarts.clear();
if (r.app != null) { if (r.app != null) {
@ -8658,6 +8696,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
? res.permission : "private to package"); ? res.permission : "private to package");
} }
ServiceRecord r = res.record; ServiceRecord r = res.record;
int targetPermissionUid = checkGrantUriPermissionFromIntentLocked(
callingUid, r.packageName, service);
if (unscheduleServiceRestartLocked(r)) { if (unscheduleServiceRestartLocked(r)) {
if (DEBUG_SERVICE) Slog.v(TAG, "START SERVICE WHILE RESTART PENDING: " if (DEBUG_SERVICE) Slog.v(TAG, "START SERVICE WHILE RESTART PENDING: "
+ r.shortName); + r.shortName);
@ -8668,7 +8708,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
if (r.lastStartId < 1) { if (r.lastStartId < 1) {
r.lastStartId = 1; r.lastStartId = 1;
} }
r.pendingStarts.add(new ServiceRecord.StartItem(r.lastStartId, service)); r.pendingStarts.add(new ServiceRecord.StartItem(r, r.lastStartId,
service, targetPermissionUid));
r.lastActivity = SystemClock.uptimeMillis(); r.lastActivity = SystemClock.uptimeMillis();
synchronized (r.stats.getBatteryStats()) { synchronized (r.stats.getBatteryStats()) {
r.stats.startRunningLocked(); r.stats.startRunningLocked();
@ -8793,7 +8834,9 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
ServiceRecord.StartItem si = r.findDeliveredStart(startId, false); ServiceRecord.StartItem si = r.findDeliveredStart(startId, false);
if (si != null) { if (si != null) {
while (r.deliveredStarts.size() > 0) { while (r.deliveredStarts.size() > 0) {
if (r.deliveredStarts.remove(0) == si) { ServiceRecord.StartItem cur = r.deliveredStarts.remove(0);
cur.removeUriPermissionsLocked();
if (cur == si) {
break; break;
} }
} }

View File

@ -29,6 +29,7 @@ import android.graphics.Bitmap;
import android.os.Bundle; import android.os.Bundle;
import android.os.Message; import android.os.Message;
import android.os.Process; import android.os.Process;
import android.os.RemoteException;
import android.os.SystemClock; import android.os.SystemClock;
import android.util.EventLog; import android.util.EventLog;
import android.util.Log; import android.util.Log;
@ -43,7 +44,7 @@ import java.util.HashSet;
/** /**
* An entry in the history stack, representing an activity. * An entry in the history stack, representing an activity.
*/ */
class ActivityRecord extends IApplicationToken.Stub { class ActivityRecord extends IApplicationToken.Stub implements UriPermissionOwner {
final ActivityManagerService service; // owner final ActivityManagerService service; // owner
final ActivityStack stack; // owner final ActivityStack stack; // owner
final ActivityInfo info; // all about me final ActivityInfo info; // all about me
@ -340,16 +341,22 @@ class ActivityRecord extends IApplicationToken.Stub {
* Deliver a new Intent to an existing activity, so that its onNewIntent() * Deliver a new Intent to an existing activity, so that its onNewIntent()
* method will be called at the proper time. * method will be called at the proper time.
*/ */
final void deliverNewIntentLocked(Intent intent) { final void deliverNewIntentLocked(int callingUid, Intent intent) {
boolean sent = false; boolean sent = false;
if (state == ActivityState.RESUMED if (state == ActivityState.RESUMED
&& app != null && app.thread != null) { && app != null && app.thread != null) {
try { try {
ArrayList<Intent> ar = new ArrayList<Intent>(); ArrayList<Intent> ar = new ArrayList<Intent>();
ar.add(new Intent(intent)); intent = new Intent(intent);
ar.add(intent);
service.grantUriPermissionFromIntentLocked(callingUid, packageName,
intent, this);
app.thread.scheduleNewIntent(ar, this); app.thread.scheduleNewIntent(ar, this);
sent = true; sent = true;
} catch (Exception e) { } catch (RemoteException e) {
Slog.w(ActivityManagerService.TAG,
"Exception thrown sending new intent to " + this, e);
} catch (NullPointerException e) {
Slog.w(ActivityManagerService.TAG, Slog.w(ActivityManagerService.TAG,
"Exception thrown sending new intent to " + this, e); "Exception thrown sending new intent to " + this, e);
} }
@ -362,23 +369,25 @@ class ActivityRecord extends IApplicationToken.Stub {
void removeUriPermissionsLocked() { void removeUriPermissionsLocked() {
if (readUriPermissions != null) { if (readUriPermissions != null) {
for (UriPermission perm : readUriPermissions) { for (UriPermission perm : readUriPermissions) {
perm.readActivities.remove(this); perm.readOwners.remove(this);
if (perm.readActivities.size() == 0 && (perm.globalModeFlags if (perm.readOwners.size() == 0 && (perm.globalModeFlags
&Intent.FLAG_GRANT_READ_URI_PERMISSION) == 0) { &Intent.FLAG_GRANT_READ_URI_PERMISSION) == 0) {
perm.modeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION; perm.modeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
service.removeUriPermissionIfNeededLocked(perm); service.removeUriPermissionIfNeededLocked(perm);
} }
} }
readUriPermissions = null;
} }
if (writeUriPermissions != null) { if (writeUriPermissions != null) {
for (UriPermission perm : writeUriPermissions) { for (UriPermission perm : writeUriPermissions) {
perm.writeActivities.remove(this); perm.writeOwners.remove(this);
if (perm.writeActivities.size() == 0 && (perm.globalModeFlags if (perm.writeOwners.size() == 0 && (perm.globalModeFlags
&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) == 0) { &Intent.FLAG_GRANT_WRITE_URI_PERMISSION) == 0) {
perm.modeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION; perm.modeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
service.removeUriPermissionIfNeededLocked(perm); service.removeUriPermissionIfNeededLocked(perm);
} }
} }
writeUriPermissions = null;
} }
} }
@ -569,6 +578,37 @@ class ActivityRecord extends IApplicationToken.Stub {
state == ActivityState.RESUMED; state == ActivityState.RESUMED;
} }
@Override
public void addReadPermission(UriPermission perm) {
if (readUriPermissions == null) {
readUriPermissions = new HashSet<UriPermission>();
}
readUriPermissions.add(perm);
}
@Override
public void addWritePermission(UriPermission perm) {
if (writeUriPermissions == null) {
writeUriPermissions = new HashSet<UriPermission>();
}
writeUriPermissions.add(perm);
}
@Override
public void removeReadPermission(UriPermission perm) {
readUriPermissions.remove(perm);
if (readUriPermissions.size() == 0) {
readUriPermissions = null;
}
}
@Override
public void removeWritePermission(UriPermission perm) {
writeUriPermissions.remove(perm);
if (writeUriPermissions.size() == 0) {
writeUriPermissions = null;
}
}
public String toString() { public String toString() {
if (stringName != null) { if (stringName != null) {

View File

@ -2033,16 +2033,6 @@ public class ActivityStack {
} }
} }
if (grantedUriPermissions != null && callingUid > 0) {
for (int i=0; i<grantedUriPermissions.length; i++) {
mService.grantUriPermissionLocked(callingUid, r.packageName,
grantedUriPermissions[i], grantedMode, r);
}
}
mService.grantUriPermissionFromIntentLocked(callingUid, r.packageName,
intent, r);
if (sourceRecord == null) { if (sourceRecord == null) {
// This activity is not being started from another... in this // This activity is not being started from another... in this
// case we -always- start a new task. // case we -always- start a new task.
@ -2150,7 +2140,7 @@ public class ActivityStack {
top.task.setIntent(r.intent, r.info); top.task.setIntent(r.intent, r.info);
} }
logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task); logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
top.deliverNewIntentLocked(r.intent); top.deliverNewIntentLocked(callingUid, r.intent);
} else { } else {
// A special case: we need to // A special case: we need to
// start the activity because it is not currently // start the activity because it is not currently
@ -2175,7 +2165,7 @@ public class ActivityStack {
if (taskTop.frontOfTask) { if (taskTop.frontOfTask) {
taskTop.task.setIntent(r.intent, r.info); taskTop.task.setIntent(r.intent, r.info);
} }
taskTop.deliverNewIntentLocked(r.intent); taskTop.deliverNewIntentLocked(callingUid, r.intent);
} else if (!r.intent.filterEquals(taskTop.task.intent)) { } else if (!r.intent.filterEquals(taskTop.task.intent)) {
// In this case we are launching the root activity // In this case we are launching the root activity
// of the task, but with a different intent. We // of the task, but with a different intent. We
@ -2243,7 +2233,7 @@ public class ActivityStack {
// is the case, so this is it! // is the case, so this is it!
return START_RETURN_INTENT_TO_CALLER; return START_RETURN_INTENT_TO_CALLER;
} }
top.deliverNewIntentLocked(r.intent); top.deliverNewIntentLocked(callingUid, r.intent);
return START_DELIVERED_TO_TOP; return START_DELIVERED_TO_TOP;
} }
} }
@ -2288,7 +2278,7 @@ public class ActivityStack {
sourceRecord.task.taskId, r, launchFlags, true); sourceRecord.task.taskId, r, launchFlags, true);
if (top != null) { if (top != null) {
logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task); logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
top.deliverNewIntentLocked(r.intent); top.deliverNewIntentLocked(callingUid, r.intent);
// For paranoia, make sure we have correctly // For paranoia, make sure we have correctly
// resumed the top activity. // resumed the top activity.
if (doResume) { if (doResume) {
@ -2305,7 +2295,7 @@ public class ActivityStack {
if (where >= 0) { if (where >= 0) {
ActivityRecord top = moveActivityToFrontLocked(where); ActivityRecord top = moveActivityToFrontLocked(where);
logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task); logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
top.deliverNewIntentLocked(r.intent); top.deliverNewIntentLocked(callingUid, r.intent);
if (doResume) { if (doResume) {
resumeTopActivityLocked(null); resumeTopActivityLocked(null);
} }
@ -2333,6 +2323,17 @@ public class ActivityStack {
if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r
+ " in new guessed " + r.task); + " in new guessed " + r.task);
} }
if (grantedUriPermissions != null && callingUid > 0) {
for (int i=0; i<grantedUriPermissions.length; i++) {
mService.grantUriPermissionLocked(callingUid, r.packageName,
grantedUriPermissions[i], grantedMode, r);
}
}
mService.grantUriPermissionFromIntentLocked(callingUid, r.packageName,
intent, r);
if (newTask) { if (newTask) {
EventLog.writeEvent(EventLogTags.AM_CREATE_TASK, r.task.taskId); EventLog.writeEvent(EventLogTags.AM_CREATE_TASK, r.task.taskId);
} }

View File

@ -26,6 +26,7 @@ import android.os.Bundle;
import android.os.IBinder; import android.os.IBinder;
import android.os.SystemClock; import android.os.SystemClock;
import android.util.PrintWriterPrinter; import android.util.PrintWriterPrinter;
import android.util.TimeUtils;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.util.List; import java.util.List;
@ -73,61 +74,65 @@ class BroadcastRecord extends Binder {
ActivityInfo curReceiver; // info about the receiver that is currently running. ActivityInfo curReceiver; // info about the receiver that is currently running.
void dump(PrintWriter pw, String prefix) { void dump(PrintWriter pw, String prefix) {
pw.println(prefix + this); final long now = SystemClock.uptimeMillis();
pw.println(prefix + intent);
pw.print(prefix); pw.println(this);
pw.print(prefix); pw.println(intent);
if (sticky) { if (sticky) {
Bundle bundle = intent.getExtras(); Bundle bundle = intent.getExtras();
if (bundle != null) { if (bundle != null) {
pw.println(prefix + "extras: " + bundle.toString()); pw.print(prefix); pw.print("extras: "); pw.println(bundle.toString());
} }
} }
pw.println(prefix + "proc=" + callerApp); pw.print(prefix); pw.print("caller="); pw.print(callerPackage); pw.println(" ");
pw.println(prefix + "caller=" + callerPackage pw.println(callerApp != null ? callerApp.toShortString() : "null");
+ " callingPid=" + callingPid pw.print(" pid="); pw.print(callingPid);
+ " callingUid=" + callingUid); pw.print(" uid="); pw.println(callingUid);
if (requiredPermission != null) { if (requiredPermission != null) {
pw.println(prefix + "requiredPermission=" + requiredPermission); pw.print(prefix); pw.print("requiredPermission="); pw.println(requiredPermission);
} }
pw.println(prefix + "dispatchTime=" + dispatchTime + " (" pw.print(prefix); pw.print("dispatchTime=");
+ (SystemClock.uptimeMillis()-dispatchTime) + "ms since now)"); TimeUtils.formatDuration(dispatchTime, now, pw);
if (finishTime != 0) { if (finishTime != 0) {
pw.println(prefix + "finishTime=" + finishTime + " (" pw.print(" finishTime="); TimeUtils.formatDuration(finishTime, now, pw);
+ (SystemClock.uptimeMillis()-finishTime) + "ms since now)");
} else { } else {
pw.println(prefix + "receiverTime=" + receiverTime + " (" pw.print(" receiverTime="); TimeUtils.formatDuration(receiverTime, now, pw);
+ (SystemClock.uptimeMillis()-receiverTime) + "ms since now)");
} }
pw.println("");
if (anrCount != 0) { if (anrCount != 0) {
pw.println(prefix + "anrCount=" + anrCount); pw.print(prefix); pw.print("anrCount="); pw.println(anrCount);
} }
if (resultTo != null || resultCode != -1 || resultData != null) { if (resultTo != null || resultCode != -1 || resultData != null) {
pw.println(prefix + "resultTo=" + resultTo pw.print(prefix); pw.print("resultTo="); pw.print(resultTo);
+ " resultCode=" + resultCode + " resultData=" + resultData); pw.print(" resultCode="); pw.print(resultCode);
pw.print(" resultData="); pw.println(resultData);
} }
if (resultExtras != null) { if (resultExtras != null) {
pw.println(prefix + "resultExtras=" + resultExtras); pw.print(prefix); pw.print("resultExtras="); pw.println(resultExtras);
} }
if (resultAbort || ordered || sticky || initialSticky) { if (resultAbort || ordered || sticky || initialSticky) {
pw.println(prefix + "resultAbort=" + resultAbort pw.print(prefix); pw.print("resultAbort="); pw.print(resultAbort);
+ " ordered=" + ordered + " sticky=" + sticky pw.print(" ordered="); pw.print(ordered);
+ " initialSticky=" + initialSticky); pw.print(" sticky="); pw.print(sticky);
pw.print(" initialSticky="); pw.println(initialSticky);
} }
if (nextReceiver != 0 || receiver != null) { if (nextReceiver != 0 || receiver != null) {
pw.println(prefix + "nextReceiver=" + nextReceiver pw.print(prefix); pw.print("nextReceiver="); pw.print(nextReceiver);
+ " receiver=" + receiver); pw.print(" receiver="); pw.println(receiver);
} }
if (curFilter != null) { if (curFilter != null) {
pw.println(prefix + "curFilter=" + curFilter); pw.print(prefix); pw.print("curFilter="); pw.println(curFilter);
} }
if (curReceiver != null) { if (curReceiver != null) {
pw.println(prefix + "curReceiver=" + curReceiver); pw.print(prefix); pw.print("curReceiver="); pw.println(curReceiver);
} }
if (curApp != null) { if (curApp != null) {
pw.println(prefix + "curApp=" + curApp); pw.print(prefix); pw.print("curApp="); pw.println(curApp);
pw.println(prefix + "curComponent=" pw.print(prefix); pw.print("curComponent=");
+ (curComponent != null ? curComponent.toShortString() : "--")); pw.println((curComponent != null ? curComponent.toShortString() : "--"));
if (curReceiver != null && curReceiver.applicationInfo != null) { if (curReceiver != null && curReceiver.applicationInfo != null) {
pw.println(prefix + "curSourceDir=" + curReceiver.applicationInfo.sourceDir); pw.print(prefix); pw.print("curSourceDir=");
pw.println(curReceiver.applicationInfo.sourceDir);
} }
} }
String stateStr = " (?)"; String stateStr = " (?)";
@ -137,13 +142,14 @@ class BroadcastRecord extends Binder {
case CALL_IN_RECEIVE: stateStr=" (CALL_IN_RECEIVE)"; break; case CALL_IN_RECEIVE: stateStr=" (CALL_IN_RECEIVE)"; break;
case CALL_DONE_RECEIVE: stateStr=" (CALL_DONE_RECEIVE)"; break; case CALL_DONE_RECEIVE: stateStr=" (CALL_DONE_RECEIVE)"; break;
} }
pw.println(prefix + "state=" + state + stateStr); pw.print(prefix); pw.print("state="); pw.print(state); pw.println(stateStr);
final int N = receivers != null ? receivers.size() : 0; final int N = receivers != null ? receivers.size() : 0;
String p2 = prefix + " "; String p2 = prefix + " ";
PrintWriterPrinter printer = new PrintWriterPrinter(pw); PrintWriterPrinter printer = new PrintWriterPrinter(pw);
for (int i=0; i<N; i++) { for (int i=0; i<N; i++) {
Object o = receivers.get(i); Object o = receivers.get(i);
pw.println(prefix + "Receiver #" + i + ": " + o); pw.print(prefix); pw.print("Receiver #"); pw.print(i);
pw.print(": "); pw.println(o);
if (o instanceof BroadcastFilter) if (o instanceof BroadcastFilter)
((BroadcastFilter)o).dumpBrief(pw, p2); ((BroadcastFilter)o).dumpBrief(pw, p2);
else if (o instanceof ResolveInfo) else if (o instanceof ResolveInfo)

View File

@ -36,6 +36,7 @@ import android.util.TimeUtils;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
@ -43,6 +44,12 @@ import java.util.List;
* A running application service. * A running application service.
*/ */
class ServiceRecord extends Binder { class ServiceRecord extends Binder {
// Maximum number of delivery attempts before giving up.
static final int MAX_DELIVERY_COUNT = 3;
// Maximum number of times it can fail during execution before giving up.
static final int MAX_DONE_EXECUTING_COUNT = 6;
final ActivityManagerService ams; final ActivityManagerService ams;
final BatteryStatsImpl.Uid.Pkg.Serv stats; final BatteryStatsImpl.Uid.Pkg.Serv stats;
final ComponentName name; // service component. final ComponentName name; // service component.
@ -69,29 +76,6 @@ class ServiceRecord extends Binder {
= new HashMap<IBinder, ConnectionRecord>(); = new HashMap<IBinder, ConnectionRecord>();
// IBinder -> ConnectionRecord of all bound clients // IBinder -> ConnectionRecord of all bound clients
// Maximum number of delivery attempts before giving up.
static final int MAX_DELIVERY_COUNT = 3;
// Maximum number of times it can fail during execution before giving up.
static final int MAX_DONE_EXECUTING_COUNT = 6;
static class StartItem {
final int id;
final Intent intent;
long deliveredTime;
int deliveryCount;
int doneExecutingCount;
StartItem(int _id, Intent _intent) {
id = _id;
intent = _intent;
}
}
final ArrayList<StartItem> deliveredStarts = new ArrayList<StartItem>();
// start() arguments which been delivered.
final ArrayList<StartItem> pendingStarts = new ArrayList<StartItem>();
// start() arguments that haven't yet been delivered.
ProcessRecord app; // where this service is running or null. ProcessRecord app; // where this service is running or null.
boolean isForeground; // is service currently in foreground mode? boolean isForeground; // is service currently in foreground mode?
int foregroundId; // Notification ID of last foreground req. int foregroundId; // Notification ID of last foreground req.
@ -112,6 +96,104 @@ class ServiceRecord extends Binder {
String stringName; // caching of toString String stringName; // caching of toString
static class StartItem implements UriPermissionOwner {
final ServiceRecord sr;
final int id;
final Intent intent;
final int targetPermissionUid;
long deliveredTime;
int deliveryCount;
int doneExecutingCount;
String stringName; // caching of toString
HashSet<UriPermission> readUriPermissions; // special access to reading uris.
HashSet<UriPermission> writeUriPermissions; // special access to writing uris.
StartItem(ServiceRecord _sr, int _id, Intent _intent, int _targetPermissionUid) {
sr = _sr;
id = _id;
intent = _intent;
targetPermissionUid = _targetPermissionUid;
}
void removeUriPermissionsLocked() {
if (readUriPermissions != null) {
for (UriPermission perm : readUriPermissions) {
perm.readOwners.remove(this);
if (perm.readOwners.size() == 0 && (perm.globalModeFlags
&Intent.FLAG_GRANT_READ_URI_PERMISSION) == 0) {
perm.modeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
sr.ams.removeUriPermissionIfNeededLocked(perm);
}
}
readUriPermissions = null;
}
if (writeUriPermissions != null) {
for (UriPermission perm : writeUriPermissions) {
perm.writeOwners.remove(this);
if (perm.writeOwners.size() == 0 && (perm.globalModeFlags
&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) == 0) {
perm.modeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
sr.ams.removeUriPermissionIfNeededLocked(perm);
}
}
writeUriPermissions = null;
}
}
@Override
public void addReadPermission(UriPermission perm) {
if (readUriPermissions == null) {
readUriPermissions = new HashSet<UriPermission>();
}
readUriPermissions.add(perm);
}
@Override
public void addWritePermission(UriPermission perm) {
if (writeUriPermissions == null) {
writeUriPermissions = new HashSet<UriPermission>();
}
writeUriPermissions.add(perm);
}
@Override
public void removeReadPermission(UriPermission perm) {
readUriPermissions.remove(perm);
if (readUriPermissions.size() == 0) {
readUriPermissions = null;
}
}
@Override
public void removeWritePermission(UriPermission perm) {
writeUriPermissions.remove(perm);
if (writeUriPermissions.size() == 0) {
writeUriPermissions = null;
}
}
public String toString() {
if (stringName != null) {
return stringName;
}
StringBuilder sb = new StringBuilder(128);
sb.append("ServiceRecord{")
.append(Integer.toHexString(System.identityHashCode(sr)))
.append(' ').append(sr.shortName)
.append(" StartItem ")
.append(Integer.toHexString(System.identityHashCode(this)))
.append(" id=").append(id).append('}');
return stringName = sb.toString();
}
}
final ArrayList<StartItem> deliveredStarts = new ArrayList<StartItem>();
// start() arguments which been delivered.
final ArrayList<StartItem> pendingStarts = new ArrayList<StartItem>();
// start() arguments that haven't yet been delivered.
void dumpStartList(PrintWriter pw, String prefix, List<StartItem> list, long now) { void dumpStartList(PrintWriter pw, String prefix, List<StartItem> list, long now) {
final int N = list.size(); final int N = list.size();
for (int i=0; i<N; i++) { for (int i=0; i<N; i++) {
@ -128,9 +210,22 @@ class ServiceRecord extends Binder {
if (si.doneExecutingCount != 0) { if (si.doneExecutingCount != 0) {
pw.print(" dxc="); pw.print(si.doneExecutingCount); pw.print(" dxc="); pw.print(si.doneExecutingCount);
} }
pw.print(" "); pw.println("");
pw.print(prefix); pw.print(" intent=");
if (si.intent != null) pw.println(si.intent.toString()); if (si.intent != null) pw.println(si.intent.toString());
else pw.println("null"); else pw.println("null");
if (si.targetPermissionUid >= 0) {
pw.print(prefix); pw.print(" targetPermissionUid=");
pw.println(si.targetPermissionUid);
}
if (si.readUriPermissions != null) {
pw.print(prefix); pw.print(" readUriPermissions=");
pw.println(si.readUriPermissions);
}
if (si.writeUriPermissions != null) {
pw.print(prefix); pw.print(" writeUriPermissions=");
pw.println(si.writeUriPermissions);
}
} }
} }
@ -324,6 +419,13 @@ class ServiceRecord extends Binder {
} }
} }
public void clearDeliveredStartsLocked() {
for (int i=deliveredStarts.size()-1; i>=0; i--) {
deliveredStarts.get(i).removeUriPermissionsLocked();
}
deliveredStarts.clear();
}
public String toString() { public String toString() {
if (stringName != null) { if (stringName != null) {
return stringName; return stringName;

View File

@ -22,13 +22,20 @@ import android.net.Uri;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.util.HashSet; import java.util.HashSet;
interface UriPermissionOwner {
void addReadPermission(UriPermission perm);
void addWritePermission(UriPermission perm);
void removeReadPermission(UriPermission perm);
void removeWritePermission(UriPermission perm);
}
class UriPermission { class UriPermission {
final int uid; final int uid;
final Uri uri; final Uri uri;
int modeFlags = 0; int modeFlags = 0;
int globalModeFlags = 0; int globalModeFlags = 0;
final HashSet<ActivityRecord> readActivities = new HashSet<ActivityRecord>(); final HashSet<UriPermissionOwner> readOwners = new HashSet<UriPermissionOwner>();
final HashSet<ActivityRecord> writeActivities = new HashSet<ActivityRecord>(); final HashSet<UriPermissionOwner> writeOwners = new HashSet<UriPermissionOwner>();
String stringName; String stringName;
@ -41,27 +48,21 @@ class UriPermission {
if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) { if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
globalModeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION; globalModeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
modeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION; modeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
if (readActivities.size() > 0) { if (readOwners.size() > 0) {
for (ActivityRecord r : readActivities) { for (UriPermissionOwner r : readOwners) {
r.readUriPermissions.remove(this); r.removeReadPermission(this);
if (r.readUriPermissions.size() == 0) {
r.readUriPermissions = null;
} }
} readOwners.clear();
readActivities.clear();
} }
} }
if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) { if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
globalModeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION; globalModeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
modeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION; modeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
if (readActivities.size() > 0) { if (readOwners.size() > 0) {
for (ActivityRecord r : readActivities) { for (UriPermissionOwner r : writeOwners) {
r.writeUriPermissions.remove(this); r.removeWritePermission(this);
if (r.writeUriPermissions.size() == 0) {
r.writeUriPermissions = null;
} }
} readOwners.clear();
readActivities.clear();
} }
} }
} }
@ -85,11 +86,17 @@ class UriPermission {
pw.print(" uid="); pw.print(uid); pw.print(" uid="); pw.print(uid);
pw.print(" globalModeFlags=0x"); pw.print(" globalModeFlags=0x");
pw.println(Integer.toHexString(globalModeFlags)); pw.println(Integer.toHexString(globalModeFlags));
if (readActivities.size() != 0) { if (readOwners.size() != 0) {
pw.print(prefix); pw.print("readActivities="); pw.println(readActivities); pw.print(prefix); pw.println("readOwners:");
for (UriPermissionOwner owner : readOwners) {
pw.print(prefix); pw.print(" * "); pw.println(owner);
}
}
if (writeOwners.size() != 0) {
pw.print(prefix); pw.println("writeOwners:");
for (UriPermissionOwner owner : writeOwners) {
pw.print(prefix); pw.print(" * "); pw.println(owner);
} }
if (writeActivities.size() != 0) {
pw.print(prefix); pw.print("writeActivities="); pw.println(writeActivities);
} }
} }
} }