diff options
4 files changed, 113 insertions, 14 deletions
diff --git a/core/java/android/content/ContentService.java b/core/java/android/content/ContentService.java index a2af55817bd5..0e83dc0fb0a2 100644 --- a/core/java/android/content/ContentService.java +++ b/core/java/android/content/ContentService.java @@ -20,17 +20,21 @@ import android.accounts.Account; import android.database.IContentObserver; import android.database.sqlite.SQLiteException; import android.net.Uri; +import android.os.Binder; import android.os.Bundle; import android.os.IBinder; import android.os.Parcel; import android.os.RemoteException; import android.os.ServiceManager; import android.util.Log; +import android.util.SparseIntArray; import android.Manifest; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; import java.util.List; /** @@ -70,6 +74,40 @@ public final class ContentService extends IContentService.Stub { } else { mSyncManager.dump(fd, pw); } + pw.println(); + pw.println("Observer tree:"); + synchronized (mRootNode) { + int[] counts = new int[2]; + final SparseIntArray pidCounts = new SparseIntArray(); + mRootNode.dumpLocked(fd, pw, args, "", " ", counts, pidCounts); + pw.println(); + ArrayList<Integer> sorted = new ArrayList<Integer>(); + for (int i=0; i<pidCounts.size(); i++) { + sorted.add(pidCounts.keyAt(i)); + } + Collections.sort(sorted, new Comparator<Integer>() { + @Override + public int compare(Integer lhs, Integer rhs) { + int lc = pidCounts.get(lhs); + int rc = pidCounts.get(rhs); + if (lc < rc) { + return 1; + } else if (lc > rc) { + return -1; + } + return 0; + } + + }); + for (int i=0; i<sorted.size(); i++) { + int pid = sorted.get(i); + pw.print(" pid "); pw.print(pid); pw.print(": "); + pw.print(pidCounts.get(pid)); pw.println(" observers"); + } + pw.println(); + pw.print(" Total number of nodes: "); pw.println(counts[0]); + pw.print(" Total number of observers: "); pw.println(counts[1]); + } } finally { restoreCallingIdentity(identityToken); } @@ -102,7 +140,8 @@ public final class ContentService extends IContentService.Stub { throw new IllegalArgumentException("You must pass a valid uri and observer"); } synchronized (mRootNode) { - mRootNode.addObserverLocked(uri, observer, notifyForDescendents, mRootNode); + mRootNode.addObserverLocked(uri, observer, notifyForDescendents, mRootNode, + Binder.getCallingUid(), Binder.getCallingPid()); if (false) Log.v(TAG, "Registered observer " + observer + " at " + uri + " with notifyForDescendents " + notifyForDescendents); } @@ -465,12 +504,17 @@ public final class ContentService extends IContentService.Stub { public static final class ObserverNode { private class ObserverEntry implements IBinder.DeathRecipient { public final IContentObserver observer; + public final int uid; + public final int pid; public final boolean notifyForDescendents; private final Object observersLock; - public ObserverEntry(IContentObserver o, boolean n, Object observersLock) { + public ObserverEntry(IContentObserver o, boolean n, Object observersLock, + int _uid, int _pid) { this.observersLock = observersLock; observer = o; + uid = _uid; + pid = _pid; notifyForDescendents = n; try { observer.asBinder().linkToDeath(this, 0); @@ -484,6 +528,16 @@ public final class ContentService extends IContentService.Stub { removeObserverLocked(observer); } } + + public void dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args, + String name, String prefix, SparseIntArray pidCounts) { + pidCounts.put(pid, pidCounts.get(pid)+1); + pw.print(prefix); pw.print(name); pw.print(": pid="); + pw.print(pid); pw.print(" uid="); + pw.print(uid); pw.print(" target="); + pw.println(Integer.toHexString(System.identityHashCode( + observer != null ? observer.asBinder() : null))); + } } public static final int INSERT_TYPE = 0; @@ -498,6 +552,37 @@ public final class ContentService extends IContentService.Stub { mName = name; } + public void dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args, + String name, String prefix, int[] counts, SparseIntArray pidCounts) { + String innerName = null; + if (mObservers.size() > 0) { + if ("".equals(name)) { + innerName = mName; + } else { + innerName = name + "/" + mName; + } + for (int i=0; i<mObservers.size(); i++) { + counts[1]++; + mObservers.get(i).dumpLocked(fd, pw, args, innerName, prefix, + pidCounts); + } + } + if (mChildren.size() > 0) { + if (innerName == null) { + if ("".equals(name)) { + innerName = mName; + } else { + innerName = name + "/" + mName; + } + } + for (int i=0; i<mChildren.size(); i++) { + counts[0]++; + mChildren.get(i).dumpLocked(fd, pw, args, innerName, prefix, + counts, pidCounts); + } + } + } + private String getUriSegment(Uri uri, int index) { if (uri != null) { if (index == 0) { @@ -518,15 +603,16 @@ public final class ContentService extends IContentService.Stub { } public void addObserverLocked(Uri uri, IContentObserver observer, - boolean notifyForDescendents, Object observersLock) { - addObserverLocked(uri, 0, observer, notifyForDescendents, observersLock); + boolean notifyForDescendents, Object observersLock, int uid, int pid) { + addObserverLocked(uri, 0, observer, notifyForDescendents, observersLock, uid, pid); } private void addObserverLocked(Uri uri, int index, IContentObserver observer, - boolean notifyForDescendents, Object observersLock) { + boolean notifyForDescendents, Object observersLock, int uid, int pid) { // If this is the leaf node add the observer if (index == countUriSegments(uri)) { - mObservers.add(new ObserverEntry(observer, notifyForDescendents, observersLock)); + mObservers.add(new ObserverEntry(observer, notifyForDescendents, observersLock, + uid, pid)); return; } @@ -539,7 +625,8 @@ public final class ContentService extends IContentService.Stub { for (int i = 0; i < N; i++) { ObserverNode node = mChildren.get(i); if (node.mName.equals(segment)) { - node.addObserverLocked(uri, index + 1, observer, notifyForDescendents, observersLock); + node.addObserverLocked(uri, index + 1, observer, notifyForDescendents, + observersLock, uid, pid); return; } } @@ -547,7 +634,8 @@ public final class ContentService extends IContentService.Stub { // No child found, create one ObserverNode node = new ObserverNode(segment); mChildren.add(node); - node.addObserverLocked(uri, index + 1, observer, notifyForDescendents, observersLock); + node.addObserverLocked(uri, index + 1, observer, notifyForDescendents, + observersLock, uid, pid); } public boolean removeObserverLocked(IContentObserver observer) { diff --git a/core/tests/coretests/src/android/content/ObserverNodeTest.java b/core/tests/coretests/src/android/content/ObserverNodeTest.java index 736c75926db4..95b8465e2d48 100644 --- a/core/tests/coretests/src/android/content/ObserverNodeTest.java +++ b/core/tests/coretests/src/android/content/ObserverNodeTest.java @@ -48,9 +48,9 @@ public class ObserverNodeTest extends AndroidTestCase { int[] nums = new int[] {4, 7, 1, 4, 2, 2, 3, 3}; // special case - root.addObserverLocked(uris[0], new TestObserver().getContentObserver(), false, root); + root.addObserverLocked(uris[0], new TestObserver().getContentObserver(), false, root, 0, 0); for(int i = 1; i < uris.length; i++) { - root.addObserverLocked(uris[i], new TestObserver().getContentObserver(), true, root); + root.addObserverLocked(uris[i], new TestObserver().getContentObserver(), true, root, 0, 0); } ArrayList<ObserverCall> calls = new ArrayList<ObserverCall>(); @@ -77,7 +77,7 @@ public class ObserverNodeTest extends AndroidTestCase { int[] nums = new int[] {7, 1, 3, 3, 1, 1, 1, 1}; for(int i = 0; i < uris.length; i++) { - root.addObserverLocked(uris[i], new TestObserver().getContentObserver(), false, root); + root.addObserverLocked(uris[i], new TestObserver().getContentObserver(), false, root, 0, 0); } ArrayList<ObserverCall> calls = new ArrayList<ObserverCall>(); diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index a8fb1ed65640..94af46d94fe2 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -3610,8 +3610,10 @@ public final class ActivityManagerService extends ActivityManagerNative String processName = app.processName; try { - thread.asBinder().linkToDeath(new AppDeathRecipient( - app, pid, thread), 0); + AppDeathRecipient adr = new AppDeathRecipient( + app, pid, thread); + thread.asBinder().linkToDeath(adr, 0); + app.deathRecipient = adr; } catch (RemoteException e) { app.resetPackageList(); startProcessLocked(app, "link fail", processName); @@ -3687,6 +3689,7 @@ public final class ActivityManagerService extends ActivityManagerNative Slog.w(TAG, "Exception thrown during bind!", e); app.resetPackageList(); + app.unlinkDeathRecipient(); startProcessLocked(app, "bind fail", processName); return false; } @@ -9210,6 +9213,7 @@ public final class ActivityManagerService extends ActivityManagerNative app.notResponding = false; app.resetPackageList(); + app.unlinkDeathRecipient(); app.thread = null; app.forcingToForeground = null; app.foregroundServices = false; @@ -9327,7 +9331,6 @@ public final class ActivityManagerService extends ActivityManagerNative // This app is persistent, so we need to keep its record around. // If it is not already on the pending app list, add it there // and start a new process for it. - app.thread = null; app.forcingToForeground = null; app.foregroundServices = false; if (mPersistentStartingProcesses.indexOf(app) < 0) { diff --git a/services/java/com/android/server/am/ProcessRecord.java b/services/java/com/android/server/am/ProcessRecord.java index 99830f93136c..9e597aa93d18 100644 --- a/services/java/com/android/server/am/ProcessRecord.java +++ b/services/java/com/android/server/am/ProcessRecord.java @@ -73,6 +73,7 @@ class ProcessRecord { int adjSeq; // Sequence id for identifying oom_adj assignment cycles int lruSeq; // Sequence id for identifying LRU update cycles CompatibilityInfo compat; // last used compatibility mode + IBinder.DeathRecipient deathRecipient; // Who is watching for the death. ComponentName instrumentationClass;// class installed to instrument app ApplicationInfo instrumentationInfo; // the application being instrumented String instrumentationProfileFile; // where to save profiling @@ -297,6 +298,13 @@ class ProcessRecord { } } + public void unlinkDeathRecipient() { + if (deathRecipient != null && thread != null) { + thread.asBinder().unlinkToDeath(deathRecipient, 0); + } + deathRecipient = null; + } + public String toShortString() { if (shortStringName != null) { return shortStringName; |