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

Commit f66adfd1 authored by Dianne Hackborn's avatar Dianne Hackborn
Browse files

Add new facility to find out when a PendingIntent is canceled.

This is just an internal API in the platform, not (yet?) available
in the SDK.  But it will be useful for system services that want to
clean up state if a pending intent that has been registered with them
is canceled (either explicitly by the app, through the app being
uninstalled, etc).

Also improve the activity manager's dump of pending intents to
organize them by package, making it much easier to read (now that
we have so many active pending intents these days).

Test: ran and booted.  no CTS, since no API.

Change-Id: Iad029cfedcd77e87357eca7da1b6ae94451dd981
parent 81bfe1f6
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -190,6 +190,8 @@ interface IActivityManager {
            int flags, in Bundle options, int userId);
    void cancelIntentSender(in IIntentSender sender);
    String getPackageForIntentSender(in IIntentSender sender);
    void registerIntentSenderCancelListener(in IIntentSender sender, in IResultReceiver receiver);
    void unregisterIntentSenderCancelListener(in IIntentSender sender, in IResultReceiver receiver);
    void enterSafeMode();
    boolean startNextMatchingActivity(in IBinder callingActivity,
            in Intent intent, in Bundle options);
+78 −15
Original line number Diff line number Diff line
@@ -71,7 +71,6 @@ import static android.os.Process.THREAD_GROUP_TOP_APP;
import static android.os.Process.THREAD_PRIORITY_BACKGROUND;
import static android.os.Process.THREAD_PRIORITY_FOREGROUND;
import static android.os.Process.getFreeMemory;
import static android.os.Process.getThreadPriority;
import static android.os.Process.getTotalMemory;
import static android.os.Process.isThreadInProcess;
import static android.os.Process.killProcess;
@@ -1688,6 +1687,7 @@ public class ActivityManagerService extends IActivityManager.Stub
    static final int REPORT_LOCKED_BOOT_COMPLETE_MSG = 64;
    static final int NOTIFY_VR_SLEEPING_MSG = 65;
    static final int SERVICE_FOREGROUND_TIMEOUT_MSG = 66;
    static final int DISPATCH_PENDING_INTENT_CANCEL_MSG = 67;
    static final int START_USER_SWITCH_FG_MSG = 712;
    static final int FIRST_ACTIVITY_STACK_MSG = 100;
@@ -1956,6 +1956,18 @@ public class ActivityManagerService extends IActivityManager.Stub
            case SERVICE_FOREGROUND_TIMEOUT_MSG: {
                mServices.serviceForegroundTimeout((ServiceRecord)msg.obj);
            } break;
            case DISPATCH_PENDING_INTENT_CANCEL_MSG: {
                RemoteCallbackList<IResultReceiver> callbacks
                        = (RemoteCallbackList<IResultReceiver>)msg.obj;
                int N = callbacks.beginBroadcast();
                for (int i = 0; i < N; i++) {
                    try {
                        callbacks.getBroadcastItem(i).send(Activity.RESULT_CANCELED, null);
                    } catch (RemoteException e) {
                    }
                }
                callbacks.finishBroadcast();
            } break;
            case UPDATE_TIME_ZONE: {
                synchronized (ActivityManagerService.this) {
                    for (int i = mLruProcesses.size() - 1 ; i >= 0 ; i--) {
@@ -6402,7 +6414,7 @@ public class ActivityManagerService extends IActivityManager.Stub
                    }
                    didSomething = true;
                    it.remove();
                    pir.canceled = true;
                    makeIntentSenderCanceledLocked(pir);
                    if (pir.key.activity != null && pir.key.activity.pendingResults != null) {
                        pir.key.activity.pendingResults.remove(pir.ref);
                    }
@@ -7412,7 +7424,7 @@ public class ActivityManagerService extends IActivityManager.Stub
                }
                return rec;
            }
            rec.canceled = true;
            makeIntentSenderCanceledLocked(rec);
            mIntentSenderRecords.remove(key);
        }
        if (noCreate) {
@@ -7516,7 +7528,7 @@ public class ActivityManagerService extends IActivityManager.Stub
                    String msg = "Permission Denial: cancelIntentSender() from pid="
                        + Binder.getCallingPid()
                        + ", uid=" + Binder.getCallingUid()
                        + " is not allowed to cancel packges "
                        + " is not allowed to cancel package "
                        + rec.key.packageName;
                    Slog.w(TAG, msg);
                    throw new SecurityException(msg);
@@ -7529,13 +7541,21 @@ public class ActivityManagerService extends IActivityManager.Stub
    }
    void cancelIntentSenderLocked(PendingIntentRecord rec, boolean cleanActivity) {
        rec.canceled = true;
        makeIntentSenderCanceledLocked(rec);
        mIntentSenderRecords.remove(rec.key);
        if (cleanActivity && rec.key.activity != null) {
            rec.key.activity.pendingResults.remove(rec.ref);
        }
    }
    void makeIntentSenderCanceledLocked(PendingIntentRecord rec) {
        rec.canceled = true;
        RemoteCallbackList<IResultReceiver> callbacks = rec.detachCancelListenersLocked();
        if (callbacks != null) {
            mHandler.obtainMessage(DISPATCH_PENDING_INTENT_CANCEL_MSG, callbacks).sendToTarget();
        }
    }
    @Override
    public String getPackageForIntentSender(IIntentSender pendingResult) {
        if (!(pendingResult instanceof PendingIntentRecord)) {
@@ -7549,6 +7569,27 @@ public class ActivityManagerService extends IActivityManager.Stub
        return null;
    }
    @Override
    public void registerIntentSenderCancelListener(IIntentSender sender, IResultReceiver receiver) {
        if (!(sender instanceof PendingIntentRecord)) {
            return;
        }
        synchronized(this) {
            ((PendingIntentRecord)sender).registerCancelListenerLocked(receiver);
        }
    }
    @Override
    public void unregisterIntentSenderCancelListener(IIntentSender sender,
            IResultReceiver receiver) {
        if (!(sender instanceof PendingIntentRecord)) {
            return;
        }
        synchronized(this) {
            ((PendingIntentRecord)sender).unregisterCancelListenerLocked(receiver);
        }
    }
    @Override
    public int getUidForIntentSender(IIntentSender sender) {
        if (sender instanceof PendingIntentRecord) {
@@ -16191,23 +16232,45 @@ public class ActivityManagerService extends IActivityManager.Stub
        pw.println("ACTIVITY MANAGER PENDING INTENTS (dumpsys activity intents)");
        if (mIntentSenderRecords.size() > 0) {
            Iterator<WeakReference<PendingIntentRecord>> it
            // Organize these by package name, so they are easier to read.
            final ArrayMap<String, ArrayList<PendingIntentRecord>> byPackage = new ArrayMap<>();
            final ArrayList<WeakReference<PendingIntentRecord>> weakRefs = new ArrayList<>();
            final Iterator<WeakReference<PendingIntentRecord>> it
                    = mIntentSenderRecords.values().iterator();
            while (it.hasNext()) {
                WeakReference<PendingIntentRecord> ref = it.next();
                PendingIntentRecord rec = ref != null ? ref.get() : null;
                if (dumpPackage != null && (rec == null
                        || !dumpPackage.equals(rec.key.packageName))) {
                if (rec == null) {
                    weakRefs.add(ref);
                    continue;
                }
                if (dumpPackage != null && !dumpPackage.equals(rec.key.packageName)) {
                    continue;
                }
                ArrayList<PendingIntentRecord> list = byPackage.get(rec.key.packageName);
                if (list == null) {
                    list = new ArrayList<>();
                    byPackage.put(rec.key.packageName, list);
                }
                list.add(rec);
            }
            for (int i = 0; i < byPackage.size(); i++) {
                ArrayList<PendingIntentRecord> intents = byPackage.valueAt(i);
                printed = true;
                if (rec != null) {
                    pw.print("  * "); pw.println(rec);
                pw.print("  * "); pw.print(byPackage.keyAt(i));
                pw.print(": "); pw.print(intents.size()); pw.println(" items");
                for (int j = 0; j < intents.size(); j++) {
                    pw.print("    #"); pw.print(j); pw.print(": "); pw.println(intents.get(j));
                    if (dumpAll) {
                        rec.dump(pw, "    ");
                        intents.get(j).dump(pw, "      ");
                    }
                } else {
                    pw.print("  * "); pw.println(ref);
                }
            }
            if (weakRefs.size() > 0) {
                printed = true;
                pw.println("  * WEAK REFS:");
                for (int i = 0; i < weakRefs.size(); i++) {
                    pw.print("    #"); pw.print(i); pw.print(": "); pw.println(weakRefs.get(i));
                }
            }
        }
@@ -23328,7 +23391,7 @@ public class ActivityManagerService extends IActivityManager.Stub
                Slog.w(TAG, "markAsSentFromNotification(): not a PendingIntentRecord: " + target);
                return;
            }
            ((PendingIntentRecord) target).setWhitelistDuration(duration);
            ((PendingIntentRecord) target).setWhitelistDurationLocked(duration);
        }
        @Override
+31 −2
Original line number Diff line number Diff line
@@ -28,12 +28,14 @@ import android.content.Intent;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.TransactionTooLargeException;
import android.os.UserHandle;
import android.util.Slog;
import android.util.TimeUtils;

import com.android.internal.os.IResultReceiver;
import com.android.server.am.ActivityStackSupervisor.ActivityContainer;

import java.io.PrintWriter;
@@ -50,6 +52,7 @@ final class PendingIntentRecord extends IIntentSender.Stub {
    boolean sent = false;
    boolean canceled = false;
    private long whitelistDuration = 0;
    private RemoteCallbackList<IResultReceiver> mCancelCallbacks;

    String stringName;
    String lastTagPrefix;
@@ -191,11 +194,31 @@ final class PendingIntentRecord extends IIntentSender.Stub {
        ref = new WeakReference<PendingIntentRecord>(this);
    }

    void setWhitelistDuration(long duration) {
    void setWhitelistDurationLocked(long duration) {
        this.whitelistDuration = duration;
        this.stringName = null;
    }

    public void registerCancelListenerLocked(IResultReceiver receiver) {
        if (mCancelCallbacks == null) {
            mCancelCallbacks = new RemoteCallbackList<>();
        }
        mCancelCallbacks.register(receiver);
    }

    public void unregisterCancelListenerLocked(IResultReceiver receiver) {
        mCancelCallbacks.unregister(receiver);
        if (mCancelCallbacks.getRegisteredCallbackCount() <= 0) {
            mCancelCallbacks = null;
        }
    }

    public RemoteCallbackList<IResultReceiver> detachCancelListenersLocked() {
        RemoteCallbackList<IResultReceiver> listeners = mCancelCallbacks;
        mCancelCallbacks = null;
        return listeners;
    }

    public void send(int code, Intent intent, String resolvedType, IIntentReceiver finishedReceiver,
            String requiredPermission, Bundle options) {
        sendInner(code, intent, resolvedType, finishedReceiver,
@@ -234,7 +257,6 @@ final class PendingIntentRecord extends IIntentSender.Stub {
                sent = true;
                if ((key.flags&PendingIntent.FLAG_ONE_SHOT) != 0) {
                    owner.cancelIntentSenderLocked(this, true);
                    canceled = true;
                }

                Intent finalIntent = key.requestIntent != null
@@ -398,6 +420,13 @@ final class PendingIntentRecord extends IIntentSender.Stub {
            TimeUtils.formatDuration(whitelistDuration, pw);
            pw.println();
        }
        if (mCancelCallbacks != null) {
            pw.print(prefix); pw.println("mCancelCallbacks:");
            for (int i = 0; i < mCancelCallbacks.getRegisteredCallbackCount(); i++) {
                pw.print(prefix); pw.print("  #"); pw.print(i); pw.print(": ");
                pw.println(mCancelCallbacks.getRegisteredCallbackItem(i));
            }
        }
    }

    public String toString() {