Fix bugs with granting permissions through onNewIntent().

It would grant the permission to the temporary ActivityRecord,
not the real one, so it never got cleaned up.

Also allow granting of permissions to services because...  well,
it would be really really useful.  And it introduces some
refactoring that we'll need to support cut/paste.

Change-Id: If521f509042e7baad7f5dc9bec84b6ba0d90ba09
This commit is contained in:
Dianne Hackborn
2010-08-19 18:01:52 -07:00
parent b755e32565
commit 39792d2262
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) {
pw.println(prefix + "permission=" + permission);
}
pw.println(prefix + "uid=" + uid + " taskAffinity=" + taskAffinity);
if (theme != 0) {
pw.println(prefix + "theme=0x" + Integer.toHexString(theme));
}
pw.println(prefix + "flags=0x" + Integer.toHexString(flags)
+ " processName=" + processName);
pw.println(prefix + "processName=" + processName);
pw.println(prefix + "taskAffinity=" + taskAffinity);
pw.println(prefix + "uid=" + uid + " flags=0x" + Integer.toHexString(flags)
+ " theme=0x" + Integer.toHexString(theme));
pw.println(prefix + "sourceDir=" + sourceDir);
pw.println(prefix + "publicSourceDir=" + publicSourceDir);
pw.println(prefix + "resourceDirs=" + resourceDirs);
if (!sourceDir.equals(publicSourceDir)) {
pw.println(prefix + "publicSourceDir=" + publicSourceDir);
}
if (resourceDirs != null) {
pw.println(prefix + "resourceDirs=" + resourceDirs);
}
pw.println(prefix + "dataDir=" + dataDir);
if (sharedLibraryFiles != null) {
pw.println(prefix + "sharedLibraryFiles=" + sharedLibraryFiles);

View File

@ -4093,16 +4093,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
| Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
if (modeFlags == 0) {
return;
return -1;
}
if (DEBUG_URI_PERMISSION) Slog.v(TAG,
"Requested grant " + targetPkg + " permission to " + uri);
"Checking grant " + targetPkg + " permission to " + uri);
final IPackageManager pm = AppGlobals.getPackageManager();
@ -4110,7 +4117,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
if (!ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
if (DEBUG_URI_PERMISSION) Slog.v(TAG,
"Can't grant URI permission for non-content URI: " + uri);
return;
return -1;
}
String name = uri.getAuthority();
@ -4127,7 +4134,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
if (pi == null) {
Slog.w(TAG, "No content provider found for: " + name);
return;
return -1;
}
int targetUid;
@ -4136,10 +4143,10 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
if (targetUid < 0) {
if (DEBUG_URI_PERMISSION) Slog.v(TAG,
"Can't grant URI permission no uid for: " + targetPkg);
return;
return -1;
}
} catch (RemoteException ex) {
return;
return -1;
}
// First... does the target actually need this permission?
@ -4147,7 +4154,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// No need to grant the target this permission.
if (DEBUG_URI_PERMISSION) Slog.v(TAG,
"Target " + targetPkg + " already has full permission to " + uri);
return;
return -1;
}
// Second... is the provider allowing granting of URI permissions?
@ -4184,12 +4191,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
// the target.
if (DEBUG_URI_PERMISSION) Slog.v(TAG,
"Granting " + targetPkg + " permission to " + uri);
"Granting " + targetPkg + "/" + targetUid + " permission to " + uri);
HashMap<Uri, UriPermission> targetUris
= mGrantedUriPermissions.get(targetUid);
@ -4205,39 +4223,65 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
perm.modeFlags |= modeFlags;
if (activity == null) {
if (owner == null) {
perm.globalModeFlags |= modeFlags;
} else if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
perm.readActivities.add(activity);
if (activity.readUriPermissions == null) {
activity.readUriPermissions = new HashSet<UriPermission>();
}
activity.readUriPermissions.add(perm);
perm.readOwners.add(owner);
owner.addReadPermission(perm);
} else if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
perm.writeActivities.add(activity);
if (activity.writeUriPermissions == null) {
activity.writeUriPermissions = new HashSet<UriPermission>();
}
activity.writeUriPermissions.add(perm);
perm.writeOwners.add(owner);
owner.addWritePermission(perm);
}
}
void grantUriPermissionFromIntentLocked(int callingUid,
String targetPkg, Intent intent, ActivityRecord activity) {
void grantUriPermissionLocked(int callingUid,
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,
"Grant URI perm to " + (intent != null ? intent.getData() : null)
"Checking URI perm to " + (intent != null ? intent.getData() : null)
+ " from " + intent + "; flags=0x"
+ Integer.toHexString(intent != null ? intent.getFlags() : 0));
if (intent == null) {
return;
return -1;
}
Uri data = intent.getData();
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;
}
grantUriPermissionLocked(callingUid, targetPkg, data,
intent.getFlags(), activity);
grantUriPermissionUncheckedFromIntentLocked(targetUid, targetPkg, intent, owner);
}
public void grantUriPermission(IApplicationThread caller, String targetPkg,
@ -8187,18 +8231,23 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
return;
}
int i = 0;
while (i < N) {
while (r.pendingStarts.size() > 0) {
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: "
+ 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
// just drop it here.
i++;
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);
if (!oomAdjusted) {
oomAdjusted = true;
@ -8212,10 +8261,6 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
flags |= Service.START_FLAG_REDELIVERY;
}
r.app.thread.scheduleServiceArgs(r, si.id, flags, si.intent);
si.deliveredTime = SystemClock.uptimeMillis();
r.deliveredStarts.add(si);
si.deliveryCount++;
i++;
} catch (RemoteException e) {
// Remote process gone... we'll let the normal cleanup take
// care of this.
@ -8225,14 +8270,6 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
break;
}
}
if (i == N) {
r.pendingStarts.clear();
} else {
while (i > 0) {
i--;
r.pendingStarts.remove(i);
}
}
}
private final boolean requestServiceBindingLocked(ServiceRecord r,
@ -8315,7 +8352,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
if (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);
@ -8335,6 +8372,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
if (N > 0) {
for (int i=N-1; i>=0; i--) {
ServiceRecord.StartItem si = r.deliveredStarts.get(i);
si.removeUriPermissionsLocked();
if (si.intent == null) {
// We'll generate this again if needed.
} else if (!allowCancel || (si.deliveryCount < ServiceRecord.MAX_DELIVERY_COUNT
@ -8574,7 +8612,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
r.foregroundNoti = null;
// Clear start entries.
r.deliveredStarts.clear();
r.clearDeliveredStartsLocked();
r.pendingStarts.clear();
if (r.app != null) {
@ -8634,6 +8672,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
? res.permission : "private to package");
}
ServiceRecord r = res.record;
int targetPermissionUid = checkGrantUriPermissionFromIntentLocked(
callingUid, r.packageName, service);
if (unscheduleServiceRestartLocked(r)) {
if (DEBUG_SERVICE) Slog.v(TAG, "START SERVICE WHILE RESTART PENDING: "
+ r.shortName);
@ -8644,7 +8684,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
if (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();
synchronized (r.stats.getBatteryStats()) {
r.stats.startRunningLocked();
@ -8769,7 +8810,9 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
ServiceRecord.StartItem si = r.findDeliveredStart(startId, false);
if (si != null) {
while (r.deliveredStarts.size() > 0) {
if (r.deliveredStarts.remove(0) == si) {
ServiceRecord.StartItem cur = r.deliveredStarts.remove(0);
cur.removeUriPermissionsLocked();
if (cur == si) {
break;
}
}

View File

@ -29,6 +29,7 @@ import android.graphics.Bitmap;
import android.os.Bundle;
import android.os.Message;
import android.os.Process;
import android.os.RemoteException;
import android.os.SystemClock;
import android.util.EventLog;
import android.util.Log;
@ -43,7 +44,7 @@ import java.util.HashSet;
/**
* 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 ActivityStack stack; // owner
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()
* method will be called at the proper time.
*/
final void deliverNewIntentLocked(Intent intent) {
final void deliverNewIntentLocked(int callingUid, Intent intent) {
boolean sent = false;
if (state == ActivityState.RESUMED
&& app != null && app.thread != null) {
try {
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);
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,
"Exception thrown sending new intent to " + this, e);
}
@ -362,23 +369,25 @@ class ActivityRecord extends IApplicationToken.Stub {
void removeUriPermissionsLocked() {
if (readUriPermissions != null) {
for (UriPermission perm : readUriPermissions) {
perm.readActivities.remove(this);
if (perm.readActivities.size() == 0 && (perm.globalModeFlags
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;
service.removeUriPermissionIfNeededLocked(perm);
service.removeUriPermissionIfNeededLocked(perm);
}
}
readUriPermissions = null;
}
if (writeUriPermissions != null) {
for (UriPermission perm : writeUriPermissions) {
perm.writeActivities.remove(this);
if (perm.writeActivities.size() == 0 && (perm.globalModeFlags
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;
service.removeUriPermissionIfNeededLocked(perm);
}
}
writeUriPermissions = null;
}
}
@ -569,6 +578,37 @@ class ActivityRecord extends IApplicationToken.Stub {
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() {
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) {
// This activity is not being started from another... in this
// case we -always- start a new task.
@ -2150,7 +2140,7 @@ public class ActivityStack {
top.task.setIntent(r.intent, r.info);
}
logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
top.deliverNewIntentLocked(r.intent);
top.deliverNewIntentLocked(callingUid, r.intent);
} else {
// A special case: we need to
// start the activity because it is not currently
@ -2175,7 +2165,7 @@ public class ActivityStack {
if (taskTop.frontOfTask) {
taskTop.task.setIntent(r.intent, r.info);
}
taskTop.deliverNewIntentLocked(r.intent);
taskTop.deliverNewIntentLocked(callingUid, r.intent);
} else if (!r.intent.filterEquals(taskTop.task.intent)) {
// In this case we are launching the root activity
// of the task, but with a different intent. We
@ -2243,7 +2233,7 @@ public class ActivityStack {
// is the case, so this is it!
return START_RETURN_INTENT_TO_CALLER;
}
top.deliverNewIntentLocked(r.intent);
top.deliverNewIntentLocked(callingUid, r.intent);
return START_DELIVERED_TO_TOP;
}
}
@ -2288,7 +2278,7 @@ public class ActivityStack {
sourceRecord.task.taskId, r, launchFlags, true);
if (top != null) {
logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
top.deliverNewIntentLocked(r.intent);
top.deliverNewIntentLocked(callingUid, r.intent);
// For paranoia, make sure we have correctly
// resumed the top activity.
if (doResume) {
@ -2305,7 +2295,7 @@ public class ActivityStack {
if (where >= 0) {
ActivityRecord top = moveActivityToFrontLocked(where);
logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
top.deliverNewIntentLocked(r.intent);
top.deliverNewIntentLocked(callingUid, r.intent);
if (doResume) {
resumeTopActivityLocked(null);
}
@ -2333,6 +2323,17 @@ public class ActivityStack {
if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r
+ " 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) {
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.SystemClock;
import android.util.PrintWriterPrinter;
import android.util.TimeUtils;
import java.io.PrintWriter;
import java.util.List;
@ -73,61 +74,65 @@ class BroadcastRecord extends Binder {
ActivityInfo curReceiver; // info about the receiver that is currently running.
void dump(PrintWriter pw, String prefix) {
pw.println(prefix + this);
pw.println(prefix + intent);
final long now = SystemClock.uptimeMillis();
pw.print(prefix); pw.println(this);
pw.print(prefix); pw.println(intent);
if (sticky) {
Bundle bundle = intent.getExtras();
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.println(prefix + "caller=" + callerPackage
+ " callingPid=" + callingPid
+ " callingUid=" + callingUid);
pw.print(prefix); pw.print("caller="); pw.print(callerPackage); pw.println(" ");
pw.println(callerApp != null ? callerApp.toShortString() : "null");
pw.print(" pid="); pw.print(callingPid);
pw.print(" uid="); pw.println(callingUid);
if (requiredPermission != null) {
pw.println(prefix + "requiredPermission=" + requiredPermission);
pw.print(prefix); pw.print("requiredPermission="); pw.println(requiredPermission);
}
pw.println(prefix + "dispatchTime=" + dispatchTime + " ("
+ (SystemClock.uptimeMillis()-dispatchTime) + "ms since now)");
pw.print(prefix); pw.print("dispatchTime=");
TimeUtils.formatDuration(dispatchTime, now, pw);
if (finishTime != 0) {
pw.println(prefix + "finishTime=" + finishTime + " ("
+ (SystemClock.uptimeMillis()-finishTime) + "ms since now)");
pw.print(" finishTime="); TimeUtils.formatDuration(finishTime, now, pw);
} else {
pw.println(prefix + "receiverTime=" + receiverTime + " ("
+ (SystemClock.uptimeMillis()-receiverTime) + "ms since now)");
pw.print(" receiverTime="); TimeUtils.formatDuration(receiverTime, now, pw);
}
pw.println("");
if (anrCount != 0) {
pw.println(prefix + "anrCount=" + anrCount);
pw.print(prefix); pw.print("anrCount="); pw.println(anrCount);
}
if (resultTo != null || resultCode != -1 || resultData != null) {
pw.println(prefix + "resultTo=" + resultTo
+ " resultCode=" + resultCode + " resultData=" + resultData);
pw.print(prefix); pw.print("resultTo="); pw.print(resultTo);
pw.print(" resultCode="); pw.print(resultCode);
pw.print(" resultData="); pw.println(resultData);
}
if (resultExtras != null) {
pw.println(prefix + "resultExtras=" + resultExtras);
pw.print(prefix); pw.print("resultExtras="); pw.println(resultExtras);
}
if (resultAbort || ordered || sticky || initialSticky) {
pw.println(prefix + "resultAbort=" + resultAbort
+ " ordered=" + ordered + " sticky=" + sticky
+ " initialSticky=" + initialSticky);
pw.print(prefix); pw.print("resultAbort="); pw.print(resultAbort);
pw.print(" ordered="); pw.print(ordered);
pw.print(" sticky="); pw.print(sticky);
pw.print(" initialSticky="); pw.println(initialSticky);
}
if (nextReceiver != 0 || receiver != null) {
pw.println(prefix + "nextReceiver=" + nextReceiver
+ " receiver=" + receiver);
pw.print(prefix); pw.print("nextReceiver="); pw.print(nextReceiver);
pw.print(" receiver="); pw.println(receiver);
}
if (curFilter != null) {
pw.println(prefix + "curFilter=" + curFilter);
pw.print(prefix); pw.print("curFilter="); pw.println(curFilter);
}
if (curReceiver != null) {
pw.println(prefix + "curReceiver=" + curReceiver);
pw.print(prefix); pw.print("curReceiver="); pw.println(curReceiver);
}
if (curApp != null) {
pw.println(prefix + "curApp=" + curApp);
pw.println(prefix + "curComponent="
+ (curComponent != null ? curComponent.toShortString() : "--"));
pw.print(prefix); pw.print("curApp="); pw.println(curApp);
pw.print(prefix); pw.print("curComponent=");
pw.println((curComponent != null ? curComponent.toShortString() : "--"));
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 = " (?)";
@ -137,13 +142,14 @@ class BroadcastRecord extends Binder {
case CALL_IN_RECEIVE: stateStr=" (CALL_IN_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;
String p2 = prefix + " ";
PrintWriterPrinter printer = new PrintWriterPrinter(pw);
for (int i=0; i<N; 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)
((BroadcastFilter)o).dumpBrief(pw, p2);
else if (o instanceof ResolveInfo)

View File

@ -36,6 +36,7 @@ import android.util.TimeUtils;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
@ -43,6 +44,12 @@ import java.util.List;
* A running application service.
*/
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 BatteryStatsImpl.Uid.Pkg.Serv stats;
final ComponentName name; // service component.
@ -68,29 +75,6 @@ class ServiceRecord extends Binder {
final HashMap<IBinder, ConnectionRecord> connections
= new HashMap<IBinder, ConnectionRecord>();
// 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.
boolean isForeground; // is service currently in foreground mode?
@ -112,6 +96,104 @@ class ServiceRecord extends Binder {
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) {
final int N = list.size();
for (int i=0; i<N; i++) {
@ -128,9 +210,22 @@ class ServiceRecord extends Binder {
if (si.doneExecutingCount != 0) {
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());
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() {
if (stringName != null) {
return stringName;

View File

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