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

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

Add facility for broadcasts receives to do work asynchronously.

You can now call goAsync() and move your work to a background thread.
If you are that kind of receiver.  You weirdo.

Also allows SharedPreferences.apply() to be committed off the main
thread after returning from onReceive().

Change-Id: I27f975910e28f230ababcaeb551eb9a78ec4fc76
parent 162b689c
Loading
Loading
Loading
Loading
+155 −0
Original line number Diff line number Diff line
@@ -40186,6 +40186,17 @@
<parameter name="makeMap" type="boolean">
</parameter>
</method>
<method name="goAsync"
 return="android.content.BroadcastReceiver.PendingResult"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="true"
 deprecated="not deprecated"
 visibility="public"
>
</method>
<method name="isInitialStickyBroadcast"
 return="boolean"
 abstract="false"
@@ -40321,6 +40332,150 @@
</parameter>
</method>
</class>
<class name="BroadcastReceiver.PendingResult"
 extends="java.lang.Object"
 abstract="false"
 static="true"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
<method name="abortBroadcast"
 return="void"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="true"
 deprecated="not deprecated"
 visibility="public"
>
</method>
<method name="clearAbortBroadcast"
 return="void"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="true"
 deprecated="not deprecated"
 visibility="public"
>
</method>
<method name="finish"
 return="void"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="true"
 deprecated="not deprecated"
 visibility="public"
>
</method>
<method name="getAbortBroadcast"
 return="boolean"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="true"
 deprecated="not deprecated"
 visibility="public"
>
</method>
<method name="getResultCode"
 return="int"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="true"
 deprecated="not deprecated"
 visibility="public"
>
</method>
<method name="getResultData"
 return="java.lang.String"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="true"
 deprecated="not deprecated"
 visibility="public"
>
</method>
<method name="getResultExtras"
 return="android.os.Bundle"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="true"
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="makeMap" type="boolean">
</parameter>
</method>
<method name="setResult"
 return="void"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="true"
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="code" type="int">
</parameter>
<parameter name="data" type="java.lang.String">
</parameter>
<parameter name="extras" type="android.os.Bundle">
</parameter>
</method>
<method name="setResultCode"
 return="void"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="true"
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="code" type="int">
</parameter>
</method>
<method name="setResultData"
 return="void"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="true"
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="data" type="java.lang.String">
</parameter>
</method>
<method name="setResultExtras"
 return="void"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="true"
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="extras" type="android.os.Bundle">
</parameter>
</method>
</class>
<class name="ClipData"
 extends="java.lang.Object"
 abstract="false"
+26 −55
Original line number Diff line number Diff line
@@ -117,12 +117,14 @@ final class RemoteServiceException extends AndroidRuntimeException {
 * {@hide}
 */
public final class ActivityThread {
    static final String TAG = "ActivityThread";
    /** @hide */
    public static final String TAG = "ActivityThread";
    private static final android.graphics.Bitmap.Config THUMBNAIL_FORMAT = Bitmap.Config.RGB_565;
    private static final boolean DEBUG = false;
    static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV;
    static final boolean DEBUG_MESSAGES = false;
    static final boolean DEBUG_BROADCAST = false;
    /** @hide */
    public static final boolean DEBUG_BROADCAST = false;
    private static final boolean DEBUG_RESULTS = false;
    private static final boolean DEBUG_BACKUP = false;
    private static final boolean DEBUG_CONFIGURATION = false;
@@ -262,18 +264,20 @@ public final class ActivityThread {
        }
    }

    private static final class ReceiverData {
    private static final class ReceiverData extends BroadcastReceiver.PendingResult {
        public ReceiverData(Intent intent, int resultCode, String resultData, Bundle resultExtras,
                boolean ordered, boolean sticky, IBinder token) {
            super(resultCode, resultData, resultExtras, TYPE_COMPONENT, ordered, sticky, token);
            this.intent = intent;
        }
        
        Intent intent;
        ActivityInfo info;
        int resultCode;
        String resultData;
        Bundle resultExtras;
        boolean sync;
        boolean resultAbort;
        public String toString() {
            return "ReceiverData{intent=" + intent + " packageName=" +
            info.packageName + " resultCode=" + resultCode
            + " resultData=" + resultData + " resultExtras=" + resultExtras + "}";
                    info.packageName + " resultCode=" + getResultCode()
                    + " resultData=" + getResultData() + " resultExtras="
                    + getResultExtras(false) + "}";
        }
    }

@@ -466,15 +470,9 @@ public final class ActivityThread {

        public final void scheduleReceiver(Intent intent, ActivityInfo info,
                int resultCode, String data, Bundle extras, boolean sync) {
            ReceiverData r = new ReceiverData();

            r.intent = intent;
            ReceiverData r = new ReceiverData(intent, resultCode, data, extras,
                    sync, false, mAppThread.asBinder());
            r.info = info;
            r.resultCode = resultCode;
            r.resultData = data;
            r.resultExtras = extras;
            r.sync = sync;

            queueOrSendMessage(H.RECEIVER, r);
        }

@@ -1799,18 +1797,12 @@ public final class ActivityThread {
        try {
            java.lang.ClassLoader cl = packageInfo.getClassLoader();
            data.intent.setExtrasClassLoader(cl);
            if (data.resultExtras != null) {
                data.resultExtras.setClassLoader(cl);
            }
            data.setExtrasClassLoader(cl);
            receiver = (BroadcastReceiver)cl.loadClass(component).newInstance();
        } catch (Exception e) {
            try {
            if (DEBUG_BROADCAST) Slog.i(TAG,
                    "Finishing failed broadcast to " + data.intent.getComponent());
                mgr.finishReceiver(mAppThread.asBinder(), data.resultCode,
                                   data.resultData, data.resultExtras, data.resultAbort);
            } catch (RemoteException ex) {
            }
            data.sendFinished(mgr);
            throw new RuntimeException(
                "Unable to instantiate receiver " + component
                + ": " + e.toString(), e);
@@ -1828,20 +1820,13 @@ public final class ActivityThread {
                + ", dir=" + packageInfo.getAppDir());

            ContextImpl context = (ContextImpl)app.getBaseContext();
            receiver.setOrderedHint(true);
            receiver.setResult(data.resultCode, data.resultData,
                data.resultExtras);
            receiver.setOrderedHint(data.sync);
            receiver.setPendingResult(data);
            receiver.onReceive(context.getReceiverRestrictedContext(),
                    data.intent);
        } catch (Exception e) {
            try {
            if (DEBUG_BROADCAST) Slog.i(TAG,
                    "Finishing failed broadcast to " + data.intent.getComponent());
                mgr.finishReceiver(mAppThread.asBinder(), data.resultCode,
                    data.resultData, data.resultExtras, data.resultAbort);
            } catch (RemoteException ex) {
            }
            data.sendFinished(mgr);
            if (!mInstrumentation.onException(receiver, e)) {
                throw new RuntimeException(
                    "Unable to start receiver " + component
@@ -1849,22 +1834,8 @@ public final class ActivityThread {
            }
        }

        QueuedWork.waitToFinish();

        try {
            if (data.sync) {
                if (DEBUG_BROADCAST) Slog.i(TAG,
                        "Finishing ordered broadcast to " + data.intent.getComponent());
                mgr.finishReceiver(
                    mAppThread.asBinder(), receiver.getResultCode(),
                    receiver.getResultData(), receiver.getResultExtras(false),
                        receiver.getAbortBroadcast());
            } else {
                if (DEBUG_BROADCAST) Slog.i(TAG,
                        "Finishing broadcast to " + data.intent.getComponent());
                mgr.finishReceiver(mAppThread.asBinder(), 0, null, null, false);
            }
        } catch (RemoteException ex) {
        if (receiver.getPendingResult() != null) {
            data.finish();
        }
    }

+35 −60
Original line number Diff line number Diff line
@@ -660,37 +660,40 @@ final class LoadedApk {
        final IntentReceiverLeaked mLocation;
        RuntimeException mUnregisterLocation;

        final class Args implements Runnable {
        final class Args extends BroadcastReceiver.PendingResult implements Runnable {
            private Intent mCurIntent;
            private int mCurCode;
            private String mCurData;
            private Bundle mCurMap;
            private boolean mCurOrdered;
            private boolean mCurSticky;
            private final boolean mOrdered;

            public Args(Intent intent, int resultCode, String resultData, Bundle resultExtras,
                    boolean ordered, boolean sticky) {
                super(resultCode, resultData, resultExtras,
                        mRegistered ? TYPE_REGISTERED : TYPE_UNREGISTERED,
                        ordered, sticky, mIIntentReceiver.asBinder());
                mCurIntent = intent;
                mOrdered = ordered;
            }
            
            public void run() {
                BroadcastReceiver receiver = mReceiver;
                final BroadcastReceiver receiver = mReceiver;
                final boolean ordered = mOrdered;
                
                if (ActivityThread.DEBUG_BROADCAST) {
                    int seq = mCurIntent.getIntExtra("seq", -1);
                    Slog.i(ActivityThread.TAG, "Dispatching broadcast " + mCurIntent.getAction()
                            + " seq=" + seq + " to " + mReceiver);
                    Slog.i(ActivityThread.TAG, "  mRegistered=" + mRegistered
                            + " mCurOrdered=" + mCurOrdered);
                            + " mOrderedHint=" + ordered);
                }
                
                IActivityManager mgr = ActivityManagerNative.getDefault();
                Intent intent = mCurIntent;
                final IActivityManager mgr = ActivityManagerNative.getDefault();
                final Intent intent = mCurIntent;
                mCurIntent = null;
                
                if (receiver == null) {
                    if (mRegistered && mCurOrdered) {
                        try {
                    if (mRegistered && ordered) {
                        if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
                                "Finishing null broadcast to " + mReceiver);
                            mgr.finishReceiver(mIIntentReceiver,
                                    mCurCode, mCurData, mCurMap, false);
                        } catch (RemoteException ex) {
                        }
                        sendFinished(mgr);
                    }
                    return;
                }
@@ -698,24 +701,14 @@ final class LoadedApk {
                try {
                    ClassLoader cl =  mReceiver.getClass().getClassLoader();
                    intent.setExtrasClassLoader(cl);
                    if (mCurMap != null) {
                        mCurMap.setClassLoader(cl);
                    }
                    receiver.setOrderedHint(true);
                    receiver.setResult(mCurCode, mCurData, mCurMap);
                    receiver.clearAbortBroadcast();
                    receiver.setOrderedHint(mCurOrdered);
                    receiver.setInitialStickyHint(mCurSticky);
                    setExtrasClassLoader(cl);
                    receiver.setPendingResult(this);
                    receiver.onReceive(mContext, intent);
                } catch (Exception e) {
                    if (mRegistered && mCurOrdered) {
                        try {
                    if (mRegistered && ordered) {
                        if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
                                "Finishing failed broadcast to " + mReceiver);
                            mgr.finishReceiver(mIIntentReceiver,
                                    mCurCode, mCurData, mCurMap, false);
                        } catch (RemoteException ex) {
                        }
                        sendFinished(mgr);
                    }
                    if (mInstrumentation == null ||
                            !mInstrumentation.onException(mReceiver, e)) {
@@ -724,17 +717,9 @@ final class LoadedApk {
                            + " in " + mReceiver, e);
                    }
                }
                if (mRegistered && mCurOrdered) {
                    try {
                        if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
                                "Finishing broadcast to " + mReceiver);
                        mgr.finishReceiver(mIIntentReceiver,
                                receiver.getResultCode(),
                                receiver.getResultData(),
                                receiver.getResultExtras(false),
                                receiver.getAbortBroadcast());
                    } catch (RemoteException ex) {
                    }
                
                if (receiver.getPendingResult() != null) {
                    finish();
                }
            }
        }
@@ -798,23 +783,13 @@ final class LoadedApk {
                Slog.i(ActivityThread.TAG, "Enqueueing broadcast " + intent.getAction() + " seq=" + seq
                        + " to " + mReceiver);
            }
            Args args = new Args();
            args.mCurIntent = intent;
            args.mCurCode = resultCode;
            args.mCurData = data;
            args.mCurMap = extras;
            args.mCurOrdered = ordered;
            args.mCurSticky = sticky;
            Args args = new Args(intent, resultCode, data, extras, ordered, sticky);
            if (!mActivityThread.post(args)) {
                if (mRegistered && ordered) {
                    IActivityManager mgr = ActivityManagerNative.getDefault();
                    try {
                    if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
                            "Finishing sync broadcast to " + mReceiver);
                        mgr.finishReceiver(mIIntentReceiver, args.mCurCode,
                                args.mCurData, args.mCurMap, false);
                    } catch (RemoteException ex) {
                    }
                    args.sendFinished(mgr);
                }
            }
        }
+10 −0
Original line number Diff line number Diff line
@@ -88,4 +88,14 @@ public class QueuedWork {
            toFinish.run();
        }
    }
    
    /**
     * Returns true if there is pending work to be done.  Note that the
     * result is out of data as soon as you receive it, so be careful how you
     * use it.
     */
    public static boolean hasPendingWork() {
        return !sPendingWorkFinishers.isEmpty();
    }
    
}
+281 −31

File changed.

Preview size limit exceeded, changes collapsed.