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