1 /*
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.am;
18 
19 import android.annotation.NonNull;
20 import android.annotation.Nullable;
21 import android.annotation.UptimeMillisLong;
22 import android.content.ContentResolver;
23 import android.content.Intent;
24 import android.os.Bundle;
25 import android.os.DropBoxManager;
26 import android.os.Handler;
27 import android.os.Trace;
28 import android.util.Slog;
29 import android.util.proto.ProtoOutputStream;
30 
31 import com.android.internal.annotations.GuardedBy;
32 import com.android.server.DropBoxManagerInternal;
33 import com.android.server.LocalServices;
34 
35 import java.io.FileDescriptor;
36 import java.io.FileOutputStream;
37 import java.io.PrintWriter;
38 import java.util.Objects;
39 import java.util.Set;
40 
41 /**
42  * Queue of broadcast intents and associated bookkeeping.
43  */
44 public abstract class BroadcastQueue {
45     public static final String TAG = "BroadcastQueue";
46     public static final String TAG_DUMP = "broadcast_queue_dump";
47 
48     final @NonNull ActivityManagerService mService;
49     final @NonNull Handler mHandler;
50     final @NonNull BroadcastSkipPolicy mSkipPolicy;
51     final @NonNull BroadcastHistory mHistory;
52     final @NonNull String mQueueName;
53 
BroadcastQueue(@onNull ActivityManagerService service, @NonNull Handler handler, @NonNull String name, @NonNull BroadcastSkipPolicy skipPolicy, @NonNull BroadcastHistory history)54     BroadcastQueue(@NonNull ActivityManagerService service, @NonNull Handler handler,
55             @NonNull String name, @NonNull BroadcastSkipPolicy skipPolicy,
56             @NonNull BroadcastHistory history) {
57         mService = Objects.requireNonNull(service);
58         mHandler = Objects.requireNonNull(handler);
59         mQueueName = Objects.requireNonNull(name);
60         mSkipPolicy = Objects.requireNonNull(skipPolicy);
61         mHistory = Objects.requireNonNull(history);
62     }
63 
logw(@onNull String msg)64     static void logw(@NonNull String msg) {
65         Slog.w(TAG, msg);
66     }
67 
logv(@onNull String msg)68     static void logv(@NonNull String msg) {
69         Slog.v(TAG, msg);
70     }
71 
checkState(boolean expression, @NonNull String msg)72     static void checkState(boolean expression, @NonNull String msg) {
73         if (!expression) {
74             throw new IllegalStateException(msg);
75         }
76     }
77 
checkStateWtf(boolean expression, @NonNull String msg)78     static void checkStateWtf(boolean expression, @NonNull String msg) {
79         if (!expression) {
80             Slog.wtf(TAG, new IllegalStateException(msg));
81         }
82     }
83 
traceBegin(@onNull String methodName)84     static int traceBegin(@NonNull String methodName) {
85         final int cookie = methodName.hashCode();
86         Trace.asyncTraceForTrackBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
87                 TAG, methodName, cookie);
88         return cookie;
89     }
90 
traceEnd(int cookie)91     static void traceEnd(int cookie) {
92         Trace.asyncTraceForTrackEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER,
93                 TAG, cookie);
94     }
95 
96     @Override
toString()97     public String toString() {
98         return mQueueName;
99     }
100 
start(@onNull ContentResolver resolver)101     public abstract void start(@NonNull ContentResolver resolver);
102 
isDelayBehindServices()103     public abstract boolean isDelayBehindServices();
104 
105     /**
106      * Return the preferred scheduling group for the given process, typically
107      * influenced by a broadcast being actively dispatched.
108      *
109      * @return scheduling group such as {@link ProcessList#SCHED_GROUP_DEFAULT},
110      *         otherwise {@link ProcessList#SCHED_GROUP_UNDEFINED} if this queue
111      *         has no opinion.
112      */
113     @GuardedBy("mService")
getPreferredSchedulingGroupLocked(@onNull ProcessRecord app)114     public abstract int getPreferredSchedulingGroupLocked(@NonNull ProcessRecord app);
115 
116     /**
117      * Enqueue the given broadcast to be eventually dispatched.
118      * <p>
119      * Callers must populate {@link BroadcastRecord#receivers} with the relevant
120      * targets before invoking this method.
121      * <p>
122      * When {@link Intent#FLAG_RECEIVER_REPLACE_PENDING} is set, this method
123      * internally handles replacement of any matching broadcasts.
124      */
125     @GuardedBy("mService")
enqueueBroadcastLocked(@onNull BroadcastRecord r)126     public abstract void enqueueBroadcastLocked(@NonNull BroadcastRecord r);
127 
128     /**
129      * Signal delivered back from the given process to indicate that it's
130      * finished processing the current broadcast being dispatched to it.
131      * <p>
132      * If this signal isn't delivered back in a timely fashion, we assume the
133      * receiver has somehow wedged and we trigger an ANR.
134      */
135     @GuardedBy("mService")
finishReceiverLocked(@onNull ProcessRecord app, int resultCode, @Nullable String resultData, @Nullable Bundle resultExtras, boolean resultAbort, boolean waitForServices)136     public abstract boolean finishReceiverLocked(@NonNull ProcessRecord app, int resultCode,
137             @Nullable String resultData, @Nullable Bundle resultExtras, boolean resultAbort,
138             boolean waitForServices);
139 
140     @GuardedBy("mService")
backgroundServicesFinishedLocked(int userId)141     public abstract void backgroundServicesFinishedLocked(int userId);
142 
143     /**
144      * Signal from OS internals that the given process has just been actively
145      * attached, and is ready to begin receiving broadcasts.
146      *
147      * @return if the queue performed an action on the given process, such as
148      *         dispatching a pending broadcast
149      */
150     @GuardedBy("mService")
onApplicationAttachedLocked(@onNull ProcessRecord app)151     public abstract boolean onApplicationAttachedLocked(@NonNull ProcessRecord app)
152             throws BroadcastDeliveryFailedException;
153 
154     /**
155      * Signal from OS internals that the given process has timed out during
156      * an attempted start and attachment.
157      */
158     @GuardedBy("mService")
onApplicationTimeoutLocked(@onNull ProcessRecord app)159     public abstract void onApplicationTimeoutLocked(@NonNull ProcessRecord app);
160 
161     /**
162      * Signal from OS internals that the given process, which had already been
163      * previously attached, has now encountered a problem such as crashing or
164      * not responding.
165      */
166     @GuardedBy("mService")
onApplicationProblemLocked(@onNull ProcessRecord app)167     public abstract void onApplicationProblemLocked(@NonNull ProcessRecord app);
168 
169     /**
170      * Signal from OS internals that the given process has been killed, and is
171      * no longer actively running.
172      */
173     @GuardedBy("mService")
onApplicationCleanupLocked(@onNull ProcessRecord app)174     public abstract void onApplicationCleanupLocked(@NonNull ProcessRecord app);
175 
176     /**
177      * Signal from OS internals that the given process is in a freezable state and will be
178      * frozen soon after.
179      */
180     @GuardedBy("mService")
onProcessFreezableChangedLocked(@onNull ProcessRecord app)181     public abstract void onProcessFreezableChangedLocked(@NonNull ProcessRecord app);
182 
183     /**
184      * Signal from OS internals that the given package (or some subset of that
185      * package) has been disabled or uninstalled, and that any pending
186      * broadcasts should be cleaned up.
187      */
188     @GuardedBy("mService")
cleanupDisabledPackageReceiversLocked(@ullable String packageName, @Nullable Set<String> filterByClasses, int userId)189     public abstract boolean cleanupDisabledPackageReceiversLocked(@Nullable String packageName,
190             @Nullable Set<String> filterByClasses, int userId);
191 
192     /**
193      * Quickly determine if this queue has broadcasts that are still waiting to
194      * be delivered at some point in the future.
195      *
196      * @see #waitForIdle
197      * @see #waitForBarrier
198      */
199     @GuardedBy("mService")
isIdleLocked()200     public abstract boolean isIdleLocked();
201 
202     /**
203      * Quickly determine if this queue has non-deferred broadcasts enqueued before the given
204      * barrier timestamp that are still waiting to be delivered.
205      *
206      * @see #waitForIdle
207      * @see #waitForBarrier
208      */
209     @GuardedBy("mService")
isBeyondBarrierLocked(@ptimeMillisLong long barrierTime)210     public abstract boolean isBeyondBarrierLocked(@UptimeMillisLong long barrierTime);
211 
212     /**
213      * Quickly determine if this queue has non-deferred broadcasts waiting to be dispatched,
214      * that match {@code intent}, as defined by {@link Intent#filterEquals(Intent)}.
215      *
216      * @see #waitForDispatched(Intent, PrintWriter)
217      */
218     @GuardedBy("mService")
isDispatchedLocked(@onNull Intent intent)219     public abstract boolean isDispatchedLocked(@NonNull Intent intent);
220 
221     /**
222      * Wait until this queue becomes completely idle.
223      * <p>
224      * Any broadcasts waiting to be delivered at some point in the future will
225      * be dispatched as quickly as possible.
226      * <p>
227      * Callers are cautioned that the queue may take a long time to go idle,
228      * since running apps can continue sending new broadcasts in perpetuity;
229      * consider using {@link #waitForBarrier} instead.
230      */
waitForIdle(@onNull PrintWriter pw)231     public abstract void waitForIdle(@NonNull PrintWriter pw);
232 
233     /**
234      * Wait until any currently waiting non-deferred broadcasts have been dispatched.
235      * <p>
236      * Any broadcasts waiting to be delivered at some point in the future will
237      * be dispatched as quickly as possible.
238      * <p>
239      * Callers are advised that this method will <em>not</em> wait for any
240      * future broadcasts that are newly enqueued after being invoked.
241      */
waitForBarrier(@onNull PrintWriter pw)242     public abstract void waitForBarrier(@NonNull PrintWriter pw);
243 
244     /**
245      * Wait until all non-deferred broadcasts matching {@code intent}, as defined by
246      * {@link Intent#filterEquals(Intent)}, have been dispatched.
247      * <p>
248      * Any broadcasts waiting to be delivered at some point in the future will
249      * be dispatched as quickly as possible.
250      */
waitForDispatched(@onNull Intent intent, @NonNull PrintWriter pw)251     public abstract void waitForDispatched(@NonNull Intent intent, @NonNull PrintWriter pw);
252 
253     /**
254      * Delays delivering broadcasts to the specified package.
255      *
256      * <p> Note that this is only valid for modern queue.
257      */
forceDelayBroadcastDelivery(@onNull String targetPackage, long delayedDurationMs)258     public void forceDelayBroadcastDelivery(@NonNull String targetPackage,
259             long delayedDurationMs) {
260         // No default implementation.
261     }
262 
263     /**
264      * Brief summary of internal state, useful for debugging purposes.
265      */
266     @GuardedBy("mService")
describeStateLocked()267     public abstract @NonNull String describeStateLocked();
268 
269     @GuardedBy("mService")
dumpDebug(@onNull ProtoOutputStream proto, long fieldId)270     public abstract void dumpDebug(@NonNull ProtoOutputStream proto, long fieldId);
271 
272     @GuardedBy("mService")
dumpLocked(@onNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args, int opti, boolean dumpConstants, boolean dumpHistory, boolean dumpAll, @Nullable String dumpPackage, boolean needSep)273     public abstract boolean dumpLocked(@NonNull FileDescriptor fd, @NonNull PrintWriter pw,
274             @NonNull String[] args, int opti, boolean dumpConstants, boolean dumpHistory,
275             boolean dumpAll, @Nullable String dumpPackage, boolean needSep);
276 
277     /**
278      * Execute {@link #dumpLocked} and store the output into
279      * {@link DropBoxManager} for later inspection.
280      */
dumpToDropBoxLocked(@ullable String msg)281     public void dumpToDropBoxLocked(@Nullable String msg) {
282         LocalServices.getService(DropBoxManagerInternal.class).addEntry(TAG_DUMP, (fd) -> {
283             try (FileOutputStream out = new FileOutputStream(fd);
284                     PrintWriter pw = new PrintWriter(out)) {
285                 pw.print("Message: ");
286                 pw.println(msg);
287                 dumpLocked(fd, pw, null, 0, false, false, false, null, false);
288                 pw.flush();
289             }
290         }, DropBoxManager.IS_TEXT);
291     }
292 }
293