Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d94b71de authored by Dianne Hackborn's avatar Dianne Hackborn Committed by Android (Google) Code Review
Browse files

Merge "Work on death recipient leaks in Activity Manager and Content Service."

parents 211f5af3 1b64e0d8
Loading
Loading
Loading
Loading
+96 −8
Original line number Diff line number Diff line
@@ -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) {
+3 −3
Original line number Diff line number Diff line
@@ -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>();
+6 −3
Original line number Diff line number Diff line
@@ -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) {
+8 −0
Original line number Diff line number Diff line
@@ -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;