1 /*
2  * Copyright (C) 2016 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.app.ActivityManager.TaskSnapshot;
20 import android.app.ITaskStackListener;
21 import android.app.ActivityManager.TaskDescription;
22 import android.content.ComponentName;
23 import android.os.Binder;
24 import android.os.Handler;
25 import android.os.Looper;
26 import android.os.Message;
27 import android.os.RemoteCallbackList;
28 import android.os.RemoteException;
29 
30 import java.util.ArrayList;
31 
32 class TaskChangeNotificationController {
33     private static final int LOG_STACK_STATE_MSG = 1;
34     private static final int NOTIFY_TASK_STACK_CHANGE_LISTENERS_MSG = 2;
35     private static final int NOTIFY_ACTIVITY_PINNED_LISTENERS_MSG = 3;
36     private static final int NOTIFY_PINNED_ACTIVITY_RESTART_ATTEMPT_LISTENERS_MSG = 4;
37     private static final int NOTIFY_PINNED_STACK_ANIMATION_ENDED_LISTENERS_MSG = 5;
38     private static final int NOTIFY_FORCED_RESIZABLE_MSG = 6;
39     private static final int NOTIFY_ACTIVITY_DISMISSING_DOCKED_STACK_MSG = 7;
40     private static final int NOTIFY_TASK_ADDED_LISTENERS_MSG = 8;
41     private static final int NOTIFY_TASK_REMOVED_LISTENERS_MSG = 9;
42     private static final int NOTIFY_TASK_MOVED_TO_FRONT_LISTENERS_MSG = 10;
43     private static final int NOTIFY_TASK_DESCRIPTION_CHANGED_LISTENERS_MSG = 11;
44     private static final int NOTIFY_ACTIVITY_REQUESTED_ORIENTATION_CHANGED_LISTENERS = 12;
45     private static final int NOTIFY_TASK_REMOVAL_STARTED_LISTENERS = 13;
46     private static final int NOTIFY_TASK_PROFILE_LOCKED_LISTENERS_MSG = 14;
47     private static final int NOTIFY_TASK_SNAPSHOT_CHANGED_LISTENERS_MSG = 15;
48     private static final int NOTIFY_PINNED_STACK_ANIMATION_STARTED_LISTENERS_MSG = 16;
49     private static final int NOTIFY_ACTIVITY_UNPINNED_LISTENERS_MSG = 17;
50     private static final int NOTIFY_ACTIVITY_LAUNCH_ON_SECONDARY_DISPLAY_FAILED_MSG = 18;
51 
52     // Delay in notifying task stack change listeners (in millis)
53     private static final int NOTIFY_TASK_STACK_CHANGE_LISTENERS_DELAY = 100;
54 
55     private final ActivityManagerService mService;
56     private final ActivityStackSupervisor mStackSupervisor;
57     private final Handler mHandler;
58 
59     // Task stack change listeners in a remote process.
60     private final RemoteCallbackList<ITaskStackListener> mRemoteTaskStackListeners =
61             new RemoteCallbackList<>();
62 
63     /*
64      * Task stack change listeners in a local process. Tracked separately so that they can be
65      * called on the same thread.
66      */
67     private final ArrayList<ITaskStackListener> mLocalTaskStackListeners = new ArrayList<>();
68 
69     private final TaskStackConsumer mNotifyTaskStackChanged = (l, m) -> {
70         l.onTaskStackChanged();
71     };
72 
73     private final TaskStackConsumer mNotifyTaskCreated = (l, m) -> {
74         l.onTaskCreated(m.arg1, (ComponentName) m.obj);
75     };
76 
77     private final TaskStackConsumer mNotifyTaskRemoved = (l, m) -> {
78         l.onTaskRemoved(m.arg1);
79     };
80 
81     private final TaskStackConsumer mNotifyTaskMovedToFront = (l, m) -> {
82         l.onTaskMovedToFront(m.arg1);
83     };
84 
85     private final TaskStackConsumer mNotifyTaskDescriptionChanged = (l, m) -> {
86         l.onTaskDescriptionChanged(m.arg1, (TaskDescription) m.obj);
87     };
88 
89     private final TaskStackConsumer mNotifyActivityRequestedOrientationChanged = (l, m) -> {
90         l.onActivityRequestedOrientationChanged(m.arg1, m.arg2);
91     };
92 
93     private final TaskStackConsumer mNotifyTaskRemovalStarted = (l, m) -> {
94         l.onTaskRemovalStarted(m.arg1);
95     };
96 
97     private final TaskStackConsumer mNotifyActivityPinned = (l, m) -> {
98         l.onActivityPinned((String) m.obj /* packageName */, m.sendingUid /* userId */,
99                 m.arg1 /* taskId */, m.arg2 /* stackId */);
100     };
101 
102     private final TaskStackConsumer mNotifyActivityUnpinned = (l, m) -> {
103         l.onActivityUnpinned();
104     };
105 
106     private final TaskStackConsumer mNotifyPinnedActivityRestartAttempt = (l, m) -> {
107         l.onPinnedActivityRestartAttempt(m.arg1 != 0);
108     };
109 
110     private final TaskStackConsumer mNotifyPinnedStackAnimationStarted = (l, m) -> {
111         l.onPinnedStackAnimationStarted();
112     };
113 
114     private final TaskStackConsumer mNotifyPinnedStackAnimationEnded = (l, m) -> {
115         l.onPinnedStackAnimationEnded();
116     };
117 
118     private final TaskStackConsumer mNotifyActivityForcedResizable = (l, m) -> {
119         l.onActivityForcedResizable((String) m.obj, m.arg1, m.arg2);
120     };
121 
122     private final TaskStackConsumer mNotifyActivityDismissingDockedStack = (l, m) -> {
123         l.onActivityDismissingDockedStack();
124     };
125 
126     private final TaskStackConsumer mNotifyActivityLaunchOnSecondaryDisplayFailed = (l, m) -> {
127         l.onActivityLaunchOnSecondaryDisplayFailed();
128     };
129 
130     private final TaskStackConsumer mNotifyTaskProfileLocked = (l, m) -> {
131         l.onTaskProfileLocked(m.arg1, m.arg2);
132     };
133 
134     private final TaskStackConsumer mNotifyTaskSnapshotChanged = (l, m) -> {
135         l.onTaskSnapshotChanged(m.arg1, (TaskSnapshot) m.obj);
136     };
137 
138     @FunctionalInterface
139     public interface TaskStackConsumer {
accept(ITaskStackListener t, Message m)140         void accept(ITaskStackListener t, Message m) throws RemoteException;
141     }
142 
143     private class MainHandler extends Handler {
MainHandler(Looper looper)144         public MainHandler(Looper looper) {
145             super(looper);
146         }
147 
148         @Override
handleMessage(Message msg)149         public void handleMessage(Message msg) {
150             switch (msg.what) {
151                 case LOG_STACK_STATE_MSG: {
152                     synchronized (mService) {
153                         mStackSupervisor.logStackState();
154                     }
155                     break;
156                 }
157                 case NOTIFY_TASK_STACK_CHANGE_LISTENERS_MSG:
158                     forAllRemoteListeners(mNotifyTaskStackChanged, msg);
159                     break;
160                 case NOTIFY_TASK_ADDED_LISTENERS_MSG:
161                     forAllRemoteListeners(mNotifyTaskCreated, msg);
162                     break;
163                 case NOTIFY_TASK_REMOVED_LISTENERS_MSG:
164                     forAllRemoteListeners(mNotifyTaskRemoved, msg);
165                     break;
166                 case NOTIFY_TASK_MOVED_TO_FRONT_LISTENERS_MSG:
167                     forAllRemoteListeners(mNotifyTaskMovedToFront, msg);
168                     break;
169                 case NOTIFY_TASK_DESCRIPTION_CHANGED_LISTENERS_MSG:
170                     forAllRemoteListeners(mNotifyTaskDescriptionChanged, msg);
171                     break;
172                 case NOTIFY_ACTIVITY_REQUESTED_ORIENTATION_CHANGED_LISTENERS:
173                     forAllRemoteListeners(mNotifyActivityRequestedOrientationChanged, msg);
174                     break;
175                 case NOTIFY_TASK_REMOVAL_STARTED_LISTENERS:
176                     forAllRemoteListeners(mNotifyTaskRemovalStarted, msg);
177                     break;
178                 case NOTIFY_ACTIVITY_PINNED_LISTENERS_MSG:
179                     forAllRemoteListeners(mNotifyActivityPinned, msg);
180                     break;
181                 case NOTIFY_ACTIVITY_UNPINNED_LISTENERS_MSG:
182                     forAllRemoteListeners(mNotifyActivityUnpinned, msg);
183                     break;
184                 case NOTIFY_PINNED_ACTIVITY_RESTART_ATTEMPT_LISTENERS_MSG:
185                     forAllRemoteListeners(mNotifyPinnedActivityRestartAttempt, msg);
186                     break;
187                 case NOTIFY_PINNED_STACK_ANIMATION_STARTED_LISTENERS_MSG:
188                     forAllRemoteListeners(mNotifyPinnedStackAnimationStarted, msg);
189                     break;
190                 case NOTIFY_PINNED_STACK_ANIMATION_ENDED_LISTENERS_MSG:
191                     forAllRemoteListeners(mNotifyPinnedStackAnimationEnded, msg);
192                     break;
193                 case NOTIFY_FORCED_RESIZABLE_MSG:
194                     forAllRemoteListeners(mNotifyActivityForcedResizable, msg);
195                     break;
196                 case NOTIFY_ACTIVITY_DISMISSING_DOCKED_STACK_MSG:
197                     forAllRemoteListeners(mNotifyActivityDismissingDockedStack, msg);
198                     break;
199                 case NOTIFY_ACTIVITY_LAUNCH_ON_SECONDARY_DISPLAY_FAILED_MSG:
200                     forAllRemoteListeners(mNotifyActivityLaunchOnSecondaryDisplayFailed, msg);
201                     break;
202                 case NOTIFY_TASK_PROFILE_LOCKED_LISTENERS_MSG:
203                     forAllRemoteListeners(mNotifyTaskProfileLocked, msg);
204                     break;
205                 case NOTIFY_TASK_SNAPSHOT_CHANGED_LISTENERS_MSG:
206                     forAllRemoteListeners(mNotifyTaskSnapshotChanged, msg);
207                     break;
208             }
209         }
210     }
211 
TaskChangeNotificationController(ActivityManagerService service, ActivityStackSupervisor stackSupervisor, Handler handler)212     public TaskChangeNotificationController(ActivityManagerService service,
213             ActivityStackSupervisor stackSupervisor, Handler handler) {
214         mService = service;
215         mStackSupervisor = stackSupervisor;
216         mHandler = new MainHandler(handler.getLooper());
217     }
218 
registerTaskStackListener(ITaskStackListener listener)219     public void registerTaskStackListener(ITaskStackListener listener) {
220         synchronized (mService) {
221             if (listener != null) {
222                 if (Binder.getCallingPid() == android.os.Process.myPid()) {
223                     if (!mLocalTaskStackListeners.contains(listener)) {
224                         mLocalTaskStackListeners.add(listener);
225                     }
226                 } else {
227                     mRemoteTaskStackListeners.register(listener);
228                 }
229             }
230         }
231     }
232 
unregisterTaskStackListener(ITaskStackListener listener)233     public void unregisterTaskStackListener(ITaskStackListener listener) {
234         synchronized (mService) {
235             if (listener != null) {
236                 if (Binder.getCallingPid() == android.os.Process.myPid()) {
237                     mLocalTaskStackListeners.remove(listener);
238                 } else {
239                     mRemoteTaskStackListeners.unregister(listener);
240                 }
241             }
242         }
243     }
244 
forAllRemoteListeners(TaskStackConsumer callback, Message message)245     private void forAllRemoteListeners(TaskStackConsumer callback, Message message) {
246         synchronized (mService) {
247             for (int i = mRemoteTaskStackListeners.beginBroadcast() - 1; i >= 0; i--) {
248                 try {
249                     // Make a one-way callback to the listener
250                     callback.accept(mRemoteTaskStackListeners.getBroadcastItem(i), message);
251                 } catch (RemoteException e) {
252                     // Handled by the RemoteCallbackList.
253                 }
254             }
255             mRemoteTaskStackListeners.finishBroadcast();
256         }
257     }
258 
forAllLocalListeners(TaskStackConsumer callback, Message message)259     private void forAllLocalListeners(TaskStackConsumer callback, Message message) {
260         synchronized (mService) {
261             for (int i = mLocalTaskStackListeners.size() - 1; i >= 0; i--) {
262                 try {
263                     callback.accept(mLocalTaskStackListeners.get(i), message);
264                 } catch (RemoteException e) {
265                     // Never thrown since this is called locally.
266                 }
267             }
268         }
269     }
270 
271     /** Notifies all listeners when the task stack has changed. */
notifyTaskStackChanged()272     void notifyTaskStackChanged() {
273         mHandler.sendEmptyMessage(LOG_STACK_STATE_MSG);
274         mHandler.removeMessages(NOTIFY_TASK_STACK_CHANGE_LISTENERS_MSG);
275         final Message msg = mHandler.obtainMessage(NOTIFY_TASK_STACK_CHANGE_LISTENERS_MSG);
276         forAllLocalListeners(mNotifyTaskStackChanged, msg);
277         // Only the main task stack change notification requires a delay.
278         mHandler.sendMessageDelayed(msg, NOTIFY_TASK_STACK_CHANGE_LISTENERS_DELAY);
279     }
280 
281     /** Notifies all listeners when an Activity is pinned. */
notifyActivityPinned(ActivityRecord r)282     void notifyActivityPinned(ActivityRecord r) {
283         mHandler.removeMessages(NOTIFY_ACTIVITY_PINNED_LISTENERS_MSG);
284         final Message msg = mHandler.obtainMessage(NOTIFY_ACTIVITY_PINNED_LISTENERS_MSG,
285                 r.getTask().taskId, r.getStackId(), r.packageName);
286         msg.sendingUid = r.userId;
287         forAllLocalListeners(mNotifyActivityPinned, msg);
288         msg.sendToTarget();
289     }
290 
291     /** Notifies all listeners when an Activity is unpinned. */
notifyActivityUnpinned()292     void notifyActivityUnpinned() {
293         mHandler.removeMessages(NOTIFY_ACTIVITY_UNPINNED_LISTENERS_MSG);
294         final Message msg = mHandler.obtainMessage(NOTIFY_ACTIVITY_UNPINNED_LISTENERS_MSG);
295         forAllLocalListeners(mNotifyActivityUnpinned, msg);
296         msg.sendToTarget();
297     }
298 
299     /**
300      * Notifies all listeners when an attempt was made to start an an activity that is already
301      * running in the pinned stack and the activity was not actually started, but the task is
302      * either brought to the front or a new Intent is delivered to it.
303      */
notifyPinnedActivityRestartAttempt(boolean clearedTask)304     void notifyPinnedActivityRestartAttempt(boolean clearedTask) {
305         mHandler.removeMessages(NOTIFY_PINNED_ACTIVITY_RESTART_ATTEMPT_LISTENERS_MSG);
306         final Message msg =
307                 mHandler.obtainMessage(NOTIFY_PINNED_ACTIVITY_RESTART_ATTEMPT_LISTENERS_MSG,
308                         clearedTask ? 1 : 0, 0);
309         forAllLocalListeners(mNotifyPinnedActivityRestartAttempt, msg);
310         msg.sendToTarget();
311     }
312 
313     /** Notifies all listeners when the pinned stack animation starts. */
notifyPinnedStackAnimationStarted()314     void notifyPinnedStackAnimationStarted() {
315         mHandler.removeMessages(NOTIFY_PINNED_STACK_ANIMATION_STARTED_LISTENERS_MSG);
316         final Message msg =
317                 mHandler.obtainMessage(NOTIFY_PINNED_STACK_ANIMATION_STARTED_LISTENERS_MSG);
318         forAllLocalListeners(mNotifyPinnedStackAnimationStarted, msg);
319         msg.sendToTarget();
320     }
321 
322     /** Notifies all listeners when the pinned stack animation ends. */
notifyPinnedStackAnimationEnded()323     void notifyPinnedStackAnimationEnded() {
324         mHandler.removeMessages(NOTIFY_PINNED_STACK_ANIMATION_ENDED_LISTENERS_MSG);
325         final Message msg =
326                 mHandler.obtainMessage(NOTIFY_PINNED_STACK_ANIMATION_ENDED_LISTENERS_MSG);
327         forAllLocalListeners(mNotifyPinnedStackAnimationEnded, msg);
328         msg.sendToTarget();
329     }
330 
notifyActivityDismissingDockedStack()331     void notifyActivityDismissingDockedStack() {
332         mHandler.removeMessages(NOTIFY_ACTIVITY_DISMISSING_DOCKED_STACK_MSG);
333         final Message msg = mHandler.obtainMessage(NOTIFY_ACTIVITY_DISMISSING_DOCKED_STACK_MSG);
334         forAllLocalListeners(mNotifyActivityDismissingDockedStack, msg);
335         msg.sendToTarget();
336     }
337 
notifyActivityForcedResizable(int taskId, int reason, String packageName)338     void notifyActivityForcedResizable(int taskId, int reason, String packageName) {
339         mHandler.removeMessages(NOTIFY_FORCED_RESIZABLE_MSG);
340         final Message msg = mHandler.obtainMessage(NOTIFY_FORCED_RESIZABLE_MSG, taskId, reason,
341                 packageName);
342         forAllLocalListeners(mNotifyActivityForcedResizable, msg);
343         msg.sendToTarget();
344     }
345 
notifyActivityLaunchOnSecondaryDisplayFailed()346     void notifyActivityLaunchOnSecondaryDisplayFailed() {
347         mHandler.removeMessages(NOTIFY_ACTIVITY_LAUNCH_ON_SECONDARY_DISPLAY_FAILED_MSG);
348         final Message msg = mHandler.obtainMessage(
349                 NOTIFY_ACTIVITY_LAUNCH_ON_SECONDARY_DISPLAY_FAILED_MSG);
350         forAllLocalListeners(mNotifyActivityLaunchOnSecondaryDisplayFailed, msg);
351         msg.sendToTarget();
352     }
353 
notifyTaskCreated(int taskId, ComponentName componentName)354     void notifyTaskCreated(int taskId, ComponentName componentName) {
355         final Message msg = mHandler.obtainMessage(NOTIFY_TASK_ADDED_LISTENERS_MSG,
356                 taskId, 0 /* unused */, componentName);
357         forAllLocalListeners(mNotifyTaskCreated, msg);
358         msg.sendToTarget();
359     }
360 
notifyTaskRemoved(int taskId)361     void notifyTaskRemoved(int taskId) {
362         final Message msg = mHandler.obtainMessage(NOTIFY_TASK_REMOVED_LISTENERS_MSG,
363                 taskId, 0 /* unused */);
364         forAllLocalListeners(mNotifyTaskRemoved, msg);
365         msg.sendToTarget();
366     }
367 
notifyTaskMovedToFront(int taskId)368     void notifyTaskMovedToFront(int taskId) {
369         final Message msg = mHandler.obtainMessage(NOTIFY_TASK_MOVED_TO_FRONT_LISTENERS_MSG,
370                 taskId, 0 /* unused */);
371         forAllLocalListeners(mNotifyTaskMovedToFront, msg);
372         msg.sendToTarget();
373     }
374 
notifyTaskDescriptionChanged(int taskId, TaskDescription taskDescription)375     void notifyTaskDescriptionChanged(int taskId, TaskDescription taskDescription) {
376         final Message msg = mHandler.obtainMessage(NOTIFY_TASK_DESCRIPTION_CHANGED_LISTENERS_MSG,
377                 taskId, 0 /* unused */, taskDescription);
378         forAllLocalListeners(mNotifyTaskDescriptionChanged, msg);
379         msg.sendToTarget();
380 
381     }
382 
notifyActivityRequestedOrientationChanged(int taskId, int orientation)383     void notifyActivityRequestedOrientationChanged(int taskId, int orientation) {
384         final Message msg = mHandler.obtainMessage(
385                 NOTIFY_ACTIVITY_REQUESTED_ORIENTATION_CHANGED_LISTENERS, taskId, orientation);
386         forAllLocalListeners(mNotifyActivityRequestedOrientationChanged, msg);
387         msg.sendToTarget();
388     }
389 
390     /**
391      * Notify listeners that the task is about to be finished before its surfaces are removed from
392      * the window manager. This allows interested parties to perform relevant animations before
393      * the window disappears.
394      */
notifyTaskRemovalStarted(int taskId)395     void notifyTaskRemovalStarted(int taskId) {
396         final Message msg = mHandler.obtainMessage(NOTIFY_TASK_REMOVAL_STARTED_LISTENERS, taskId,
397                 0 /* unused */);
398         forAllLocalListeners(mNotifyTaskRemovalStarted, msg);
399         msg.sendToTarget();
400 
401     }
402 
403     /**
404      * Notify listeners that the task has been put in a locked state because one or more of the
405      * activities inside it belong to a managed profile user that has been locked.
406      */
notifyTaskProfileLocked(int taskId, int userId)407     void notifyTaskProfileLocked(int taskId, int userId) {
408         final Message msg = mHandler.obtainMessage(NOTIFY_TASK_PROFILE_LOCKED_LISTENERS_MSG, taskId,
409                 userId);
410         forAllLocalListeners(mNotifyTaskProfileLocked, msg);
411         msg.sendToTarget();
412     }
413 
414     /**
415      * Notify listeners that the snapshot of a task has changed.
416      */
notifyTaskSnapshotChanged(int taskId, TaskSnapshot snapshot)417     void notifyTaskSnapshotChanged(int taskId, TaskSnapshot snapshot) {
418         final Message msg = mHandler.obtainMessage(NOTIFY_TASK_SNAPSHOT_CHANGED_LISTENERS_MSG,
419                 taskId, 0, snapshot);
420         forAllLocalListeners(mNotifyTaskSnapshotChanged, msg);
421         msg.sendToTarget();
422     }
423 }
424