diff options
Diffstat (limited to 'services/java')
7 files changed, 373 insertions, 175 deletions
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index 9d31502..b37cd89 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -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; } } diff --git a/services/java/com/android/server/am/ActivityRecord.java b/services/java/com/android/server/am/ActivityRecord.java index 79756a7..80a41b7 100644 --- a/services/java/com/android/server/am/ActivityRecord.java +++ b/services/java/com/android/server/am/ActivityRecord.java @@ -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) { diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java index de7b15c..a5f7e96 100644 --- a/services/java/com/android/server/am/ActivityStack.java +++ b/services/java/com/android/server/am/ActivityStack.java @@ -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); } diff --git a/services/java/com/android/server/am/BroadcastRecord.java b/services/java/com/android/server/am/BroadcastRecord.java index c3f0b3e..bac21b1 100644 --- a/services/java/com/android/server/am/BroadcastRecord.java +++ b/services/java/com/android/server/am/BroadcastRecord.java @@ -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) diff --git a/services/java/com/android/server/am/ServiceRecord.java b/services/java/com/android/server/am/ServiceRecord.java index ab5a78d..255fbe3 100644 --- a/services/java/com/android/server/am/ServiceRecord.java +++ b/services/java/com/android/server/am/ServiceRecord.java @@ -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; diff --git a/services/java/com/android/server/am/UriPermission.java b/services/java/com/android/server/am/UriPermission.java index 81450c5..93c59cc 100644 --- a/services/java/com/android/server/am/UriPermission.java +++ b/services/java/com/android/server/am/UriPermission.java @@ -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); + } } } } diff --git a/services/java/com/android/server/sip/SipSessionGroup.java b/services/java/com/android/server/sip/SipSessionGroup.java index db3f536..d33558b 100644 --- a/services/java/com/android/server/sip/SipSessionGroup.java +++ b/services/java/com/android/server/sip/SipSessionGroup.java @@ -381,14 +381,29 @@ class SipSessionGroup implements SipListener { : listener); } + // process the command in a new thread + private void doCommandAsync(final EventObject command) { + new Thread(new Runnable() { + public void run() { + try { + processCommand(command); + } catch (SipException e) { + // TODO: find a better way to do this + if ((command instanceof RegisterCommand) + || (command == DEREGISTER)) { + onRegistrationFailed(e); + } else { + onError(e); + } + } + } + }).start(); + } + public void makeCall(SipProfile peerProfile, SessionDescription sessionDescription) { - try { - processCommand( - new MakeCallCommand(peerProfile, sessionDescription)); - } catch (SipException e) { - onError(e); - } + doCommandAsync( + new MakeCallCommand(peerProfile, sessionDescription)); } public void answerCall(SessionDescription sessionDescription) { @@ -401,36 +416,20 @@ class SipSessionGroup implements SipListener { } public void endCall() { - try { - processCommand(END_CALL); - } catch (SipException e) { - onError(e); - } + doCommandAsync(END_CALL); } public void changeCall(SessionDescription sessionDescription) { - try { - processCommand( - new MakeCallCommand(mPeerProfile, sessionDescription)); - } catch (SipException e) { - onError(e); - } + doCommandAsync( + new MakeCallCommand(mPeerProfile, sessionDescription)); } public void register(int duration) { - try { - processCommand(new RegisterCommand(duration)); - } catch (SipException e) { - onRegistrationFailed(e); - } + doCommandAsync(new RegisterCommand(duration)); } public void unregister() { - try { - processCommand(DEREGISTER); - } catch (SipException e) { - onRegistrationFailed(e); - } + doCommandAsync(DEREGISTER); } public boolean isReRegisterRequired() { |
