blob: 09df7e20a3e970d424a9ad807586cfa9ea095f1a [file] [log] [blame]
Winson Chungda2818f2017-10-23 16:25:49 -07001/*
2 * Copyright (C) 2017 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
17package com.android.server.am;
18
19import static android.app.ActivityManager.ASSIST_CONTEXT_FULL;
20import static android.app.AppOpsManager.MODE_ALLOWED;
21import static android.app.AppOpsManager.OP_NONE;
Winson Chungfbbb1582018-11-13 16:09:01 -080022
Wale Ogunwale9e4f3e02018-05-17 09:35:39 -070023import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_RECEIVER_EXTRAS;
Winson Chungda2818f2017-10-23 16:25:49 -070024
Wale Ogunwale04d9cb52018-04-30 13:55:07 -070025import android.app.ActivityTaskManager;
Winson Chungda2818f2017-10-23 16:25:49 -070026import android.app.AppOpsManager;
Winson Chunge2104682017-11-08 17:31:14 -080027import android.app.IAssistDataReceiver;
Winson Chungda2818f2017-10-23 16:25:49 -070028import android.content.Context;
29import android.graphics.Bitmap;
30import android.os.Bundle;
31import android.os.IBinder;
32import android.os.RemoteException;
33import android.view.IWindowManager;
34
35import com.android.internal.annotations.GuardedBy;
Winson Chungda2818f2017-10-23 16:25:49 -070036import com.android.internal.logging.MetricsLogger;
37
38import java.io.PrintWriter;
39import java.util.ArrayList;
40import java.util.List;
41
42/**
43 * Helper class to asynchronously fetch the assist data and screenshot from the current running
44 * activities. It manages received data and calls back to the owner when the owner is ready to
45 * receive the data itself.
46 */
47public class AssistDataRequester extends IAssistDataReceiver.Stub {
48
49 public static final String KEY_RECEIVER_EXTRA_COUNT = "count";
50 public static final String KEY_RECEIVER_EXTRA_INDEX = "index";
51
Winson Chungda2818f2017-10-23 16:25:49 -070052 private IWindowManager mWindowManager;
53 private Context mContext;
54 private AppOpsManager mAppOpsManager;
55
56 private AssistDataRequesterCallbacks mCallbacks;
57 private Object mCallbacksLock;
58
59 private int mRequestStructureAppOps;
60 private int mRequestScreenshotAppOps;
61 private boolean mCanceled;
62 private int mPendingDataCount;
63 private int mPendingScreenshotCount;
64 private final ArrayList<Bundle> mAssistData = new ArrayList<>();
65 private final ArrayList<Bitmap> mAssistScreenshot = new ArrayList<>();
66
67
68 /**
69 * Interface to handle the events from the fetcher.
70 */
71 public interface AssistDataRequesterCallbacks {
72 /**
73 * @return whether the currently received assist data can be handled by the callbacks.
74 */
75 @GuardedBy("mCallbacksLock")
76 boolean canHandleReceivedAssistDataLocked();
77
78 /**
79 * Called when we receive asynchronous assist data. This call is only made if the
80 * {@param fetchData} argument to requestAssistData() is true, and if the current activity
81 * allows assist data to be fetched. In addition, the callback will be made with the
82 * {@param mCallbacksLock} held, and only if {@link #canHandleReceivedAssistDataLocked()}
83 * is true.
84 */
85 @GuardedBy("mCallbacksLock")
Winson Chungfbbb1582018-11-13 16:09:01 -080086 default void onAssistDataReceivedLocked(Bundle data, int activityIndex, int activityCount) {
87 // Do nothing
88 }
Winson Chungda2818f2017-10-23 16:25:49 -070089
90 /**
91 * Called when we receive asynchronous assist screenshot. This call is only made if
92 * {@param fetchScreenshot} argument to requestAssistData() is true, and if the current
93 * activity allows assist data to be fetched. In addition, the callback will be made with
94 * the {@param mCallbacksLock} held, and only if
95 * {@link #canHandleReceivedAssistDataLocked()} is true.
96 */
97 @GuardedBy("mCallbacksLock")
Winson Chungfbbb1582018-11-13 16:09:01 -080098 default void onAssistScreenshotReceivedLocked(Bitmap screenshot) {
99 // Do nothing
100 }
Winson Chung397967f2017-11-01 16:21:35 -0700101
102 /**
103 * Called when there is no more pending assist data or screenshots for the last request.
104 * If the request was canceled, then this callback will not be made. In addition, the
105 * callback will be made with the {@param mCallbacksLock} held, and only if
106 * {@link #canHandleReceivedAssistDataLocked()} is true.
107 */
108 @GuardedBy("mCallbacksLock")
109 default void onAssistRequestCompleted() {
110 // Do nothing
111 }
Winson Chungda2818f2017-10-23 16:25:49 -0700112 }
113
114 /**
115 * @param callbacks The callbacks to handle the asynchronous reply with the assist data.
116 * @param callbacksLock The lock for the requester to hold when calling any of the
117 * {@param callbacks}. The owner should also take care in locking
118 * appropriately when calling into this requester.
119 * @param requestStructureAppOps The app ops to check before requesting the assist structure
120 * @param requestScreenshotAppOps The app ops to check before requesting the assist screenshot.
121 * This can be {@link AppOpsManager#OP_NONE} to indicate that
122 * screenshots should never be fetched.
123 */
Wale Ogunwalea6191b42018-05-09 07:41:32 -0700124 public AssistDataRequester(Context context,
Winson Chungda2818f2017-10-23 16:25:49 -0700125 IWindowManager windowManager, AppOpsManager appOpsManager,
126 AssistDataRequesterCallbacks callbacks, Object callbacksLock,
127 int requestStructureAppOps, int requestScreenshotAppOps) {
128 mCallbacks = callbacks;
129 mCallbacksLock = callbacksLock;
130 mWindowManager = windowManager;
Winson Chungda2818f2017-10-23 16:25:49 -0700131 mContext = context;
132 mAppOpsManager = appOpsManager;
133 mRequestStructureAppOps = requestStructureAppOps;
134 mRequestScreenshotAppOps = requestScreenshotAppOps;
135 }
136
137 /**
Winson Chung48b2bbd2018-11-15 16:02:56 -0800138 * Request that autofill data be loaded asynchronously. The resulting data will be provided
139 * through the {@link AssistDataRequesterCallbacks}.
140 *
141 * See {@link #requestData(List, boolean, boolean, boolean, boolean, boolean, int, String)}.
142 */
143 public void requestAutofillData(List<IBinder> activityTokens, int callingUid,
144 String callingPackage) {
145 requestData(activityTokens, true /* requestAutofillData */,
146 true /* fetchData */, false /* fetchScreenshot */,
147 true /* allowFetchData */, false /* allowFetchScreenshot */,
148 callingUid, callingPackage);
149 }
150
151 /**
152 * Request that assist data be loaded asynchronously. The resulting data will be provided
153 * through the {@link AssistDataRequesterCallbacks}.
154 *
155 * See {@link #requestData(List, boolean, boolean, boolean, boolean, boolean, int, String)}.
156 */
157 public void requestAssistData(List<IBinder> activityTokens, final boolean fetchData,
158 final boolean fetchScreenshot, boolean allowFetchData, boolean allowFetchScreenshot,
159 int callingUid, String callingPackage) {
160 requestData(activityTokens, false /* requestAutofillData */, fetchData, fetchScreenshot,
161 allowFetchData, allowFetchScreenshot, callingUid, callingPackage);
162 }
163
164 /**
Winson Chungda2818f2017-10-23 16:25:49 -0700165 * Request that assist data be loaded asynchronously. The resulting data will be provided
166 * through the {@link AssistDataRequesterCallbacks}.
167 *
168 * @param activityTokens the list of visible activities
Winson Chung48b2bbd2018-11-15 16:02:56 -0800169 * @param requestAutofillData if true, will fetch the autofill data, otherwise, will fetch the
170 * assist context data
Winson Chungda2818f2017-10-23 16:25:49 -0700171 * @param fetchData whether or not to fetch the assist data, only applies if the caller is
172 * allowed to fetch the assist data, and the current activity allows assist data to be
173 * fetched from it
174 * @param fetchScreenshot whether or not to fetch the screenshot, only applies if fetchData is
175 * true, the caller is allowed to fetch the assist data, and the current activity allows
176 * assist data to be fetched from it
Winson Chung60f493d2017-11-01 16:02:22 -0700177 * @param allowFetchData to be joined with other checks, determines whether or not the requester
178 * is allowed to fetch the assist data
179 * @param allowFetchScreenshot to be joined with other checks, determines whether or not the
180 * requester is allowed to fetch the assist screenshot
Winson Chungda2818f2017-10-23 16:25:49 -0700181 */
Winson Chung48b2bbd2018-11-15 16:02:56 -0800182 private void requestData(List<IBinder> activityTokens, final boolean requestAutofillData,
183 final boolean fetchData, final boolean fetchScreenshot, boolean allowFetchData,
184 boolean allowFetchScreenshot, int callingUid, String callingPackage) {
Winson Chung397967f2017-11-01 16:21:35 -0700185 // TODO(b/34090158): Known issue, if the assist data is not allowed on the current activity,
186 // then no assist data is requested for any of the other activities
Winson Chungda2818f2017-10-23 16:25:49 -0700187
188 // Early exit if there are no activity to fetch for
189 if (activityTokens.isEmpty()) {
Winson Chung397967f2017-11-01 16:21:35 -0700190 // No activities, just dispatch request-complete
191 tryDispatchRequestComplete();
Winson Chungda2818f2017-10-23 16:25:49 -0700192 return;
193 }
194
195 // Ensure that the current activity supports assist data
196 boolean isAssistDataAllowed = false;
197 try {
Wale Ogunwale04d9cb52018-04-30 13:55:07 -0700198 isAssistDataAllowed =
199 ActivityTaskManager.getService().isAssistDataAllowedOnCurrentActivity();
Winson Chungda2818f2017-10-23 16:25:49 -0700200 } catch (RemoteException e) {
201 // Should never happen
202 }
Winson Chung60f493d2017-11-01 16:02:22 -0700203 allowFetchData &= isAssistDataAllowed;
204 allowFetchScreenshot &= fetchData && isAssistDataAllowed
Winson Chungda2818f2017-10-23 16:25:49 -0700205 && (mRequestScreenshotAppOps != OP_NONE);
206
207 mCanceled = false;
208 mPendingDataCount = 0;
209 mPendingScreenshotCount = 0;
210 mAssistData.clear();
211 mAssistScreenshot.clear();
212
213 if (fetchData) {
214 if (mAppOpsManager.checkOpNoThrow(mRequestStructureAppOps, callingUid, callingPackage)
Winson Chung60f493d2017-11-01 16:02:22 -0700215 == MODE_ALLOWED && allowFetchData) {
Winson Chungda2818f2017-10-23 16:25:49 -0700216 final int numActivities = activityTokens.size();
217 for (int i = 0; i < numActivities; i++) {
218 IBinder topActivity = activityTokens.get(i);
219 try {
220 MetricsLogger.count(mContext, "assist_with_context", 1);
221 Bundle receiverExtras = new Bundle();
222 receiverExtras.putInt(KEY_RECEIVER_EXTRA_INDEX, i);
223 receiverExtras.putInt(KEY_RECEIVER_EXTRA_COUNT, numActivities);
Winson Chung48b2bbd2018-11-15 16:02:56 -0800224 boolean result = requestAutofillData
Winson Chung91f8c352018-11-26 13:32:06 -0800225 ? ActivityTaskManager.getService().requestAutofillData(this,
226 receiverExtras, topActivity, 0 /* flags */)
227 : ActivityTaskManager.getService().requestAssistContextExtras(
Winson Chung48b2bbd2018-11-15 16:02:56 -0800228 ASSIST_CONTEXT_FULL, this, receiverExtras, topActivity,
Winson Chung91f8c352018-11-26 13:32:06 -0800229 /* focused= */ i == 0, /* newSessionId= */ i == 0);
Winson Chung48b2bbd2018-11-15 16:02:56 -0800230 if (result) {
Winson Chungda2818f2017-10-23 16:25:49 -0700231 mPendingDataCount++;
232 } else if (i == 0) {
233 // Wasn't allowed... given that, let's not do the screenshot either.
Winson Chung60f493d2017-11-01 16:02:22 -0700234 if (mCallbacks.canHandleReceivedAssistDataLocked()) {
235 dispatchAssistDataReceived(null);
236 } else {
237 mAssistData.add(null);
238 }
239 allowFetchScreenshot = false;
Winson Chungda2818f2017-10-23 16:25:49 -0700240 break;
241 }
242 } catch (RemoteException e) {
243 // Can't happen
244 }
245 }
246 } else {
247 // Wasn't allowed... given that, let's not do the screenshot either.
Winson Chung60f493d2017-11-01 16:02:22 -0700248 if (mCallbacks.canHandleReceivedAssistDataLocked()) {
249 dispatchAssistDataReceived(null);
250 } else {
251 mAssistData.add(null);
252 }
253 allowFetchScreenshot = false;
Winson Chungda2818f2017-10-23 16:25:49 -0700254 }
255 }
256
257 if (fetchScreenshot) {
258 if (mAppOpsManager.checkOpNoThrow(mRequestScreenshotAppOps, callingUid, callingPackage)
Winson Chung60f493d2017-11-01 16:02:22 -0700259 == MODE_ALLOWED && allowFetchScreenshot) {
Winson Chungda2818f2017-10-23 16:25:49 -0700260 try {
261 MetricsLogger.count(mContext, "assist_with_screen", 1);
262 mPendingScreenshotCount++;
263 mWindowManager.requestAssistScreenshot(this);
264 } catch (RemoteException e) {
265 // Can't happen
266 }
267 } else {
Winson Chung60f493d2017-11-01 16:02:22 -0700268 if (mCallbacks.canHandleReceivedAssistDataLocked()) {
269 dispatchAssistScreenshotReceived(null);
270 } else {
271 mAssistScreenshot.add(null);
272 }
Winson Chungda2818f2017-10-23 16:25:49 -0700273 }
274 }
Winson Chung397967f2017-11-01 16:21:35 -0700275 // For the cases where we dispatch null data/screenshot due to permissions, just dispatch
276 // request-complete after those are made
277 tryDispatchRequestComplete();
Winson Chungda2818f2017-10-23 16:25:49 -0700278 }
279
280 /**
281 * This call should only be made when the callbacks are capable of handling the received assist
Winson Chung60f493d2017-11-01 16:02:22 -0700282 * data. The owner is also responsible for locking before calling this method.
Winson Chungda2818f2017-10-23 16:25:49 -0700283 */
284 public void processPendingAssistData() {
Winson Chung397967f2017-11-01 16:21:35 -0700285 flushPendingAssistData();
286 tryDispatchRequestComplete();
287 }
288
289 private void flushPendingAssistData() {
Winson Chungda2818f2017-10-23 16:25:49 -0700290 final int dataCount = mAssistData.size();
291 for (int i = 0; i < dataCount; i++) {
292 dispatchAssistDataReceived(mAssistData.get(i));
293 }
Winson Chung60f493d2017-11-01 16:02:22 -0700294 mAssistData.clear();
Winson Chungda2818f2017-10-23 16:25:49 -0700295 final int screenshotsCount = mAssistScreenshot.size();
296 for (int i = 0; i < screenshotsCount; i++) {
297 dispatchAssistScreenshotReceived(mAssistScreenshot.get(i));
298 }
Winson Chung60f493d2017-11-01 16:02:22 -0700299 mAssistScreenshot.clear();
Winson Chungda2818f2017-10-23 16:25:49 -0700300 }
301
302 public int getPendingDataCount() {
303 return mPendingDataCount;
304 }
305
306 public int getPendingScreenshotCount() {
307 return mPendingScreenshotCount;
308 }
309
310 /**
311 * Cancels the current request for the assist data.
312 */
313 public void cancel() {
314 // Reset the pending data count, if we receive new assist data after this point, it will
315 // be ignored
316 mCanceled = true;
317 mPendingDataCount = 0;
318 mPendingScreenshotCount = 0;
319 mAssistData.clear();
320 mAssistScreenshot.clear();
321 }
322
323 @Override
324 public void onHandleAssistData(Bundle data) {
325 synchronized (mCallbacksLock) {
326 if (mCanceled) {
327 return;
328 }
329 mPendingDataCount--;
330
331 if (mCallbacks.canHandleReceivedAssistDataLocked()) {
332 // Process any pending data and dispatch the new data as well
Winson Chung397967f2017-11-01 16:21:35 -0700333 flushPendingAssistData();
Winson Chungda2818f2017-10-23 16:25:49 -0700334 dispatchAssistDataReceived(data);
Winson Chung397967f2017-11-01 16:21:35 -0700335 tryDispatchRequestComplete();
Winson Chungda2818f2017-10-23 16:25:49 -0700336 } else {
337 // Queue up the data for processing later
338 mAssistData.add(data);
339 }
340 }
341 }
342
343 @Override
344 public void onHandleAssistScreenshot(Bitmap screenshot) {
345 synchronized (mCallbacksLock) {
346 if (mCanceled) {
347 return;
348 }
349 mPendingScreenshotCount--;
350
351 if (mCallbacks.canHandleReceivedAssistDataLocked()) {
352 // Process any pending data and dispatch the new data as well
Winson Chung397967f2017-11-01 16:21:35 -0700353 flushPendingAssistData();
Winson Chungda2818f2017-10-23 16:25:49 -0700354 dispatchAssistScreenshotReceived(screenshot);
Winson Chung397967f2017-11-01 16:21:35 -0700355 tryDispatchRequestComplete();
Winson Chungda2818f2017-10-23 16:25:49 -0700356 } else {
357 // Queue up the data for processing later
358 mAssistScreenshot.add(screenshot);
359 }
360 }
361 }
362
363 private void dispatchAssistDataReceived(Bundle data) {
364 int activityIndex = 0;
365 int activityCount = 0;
Winson Chungec1ef092017-10-25 16:22:34 -0700366 final Bundle receiverExtras = data != null
367 ? data.getBundle(ASSIST_KEY_RECEIVER_EXTRAS) : null;
Winson Chungda2818f2017-10-23 16:25:49 -0700368 if (receiverExtras != null) {
369 activityIndex = receiverExtras.getInt(KEY_RECEIVER_EXTRA_INDEX);
370 activityCount = receiverExtras.getInt(KEY_RECEIVER_EXTRA_COUNT);
371 }
372 mCallbacks.onAssistDataReceivedLocked(data, activityIndex, activityCount);
373 }
374
375 private void dispatchAssistScreenshotReceived(Bitmap screenshot) {
376 mCallbacks.onAssistScreenshotReceivedLocked(screenshot);
377 }
378
Winson Chung397967f2017-11-01 16:21:35 -0700379 private void tryDispatchRequestComplete() {
380 if (mPendingDataCount == 0 && mPendingScreenshotCount == 0 &&
381 mAssistData.isEmpty() && mAssistScreenshot.isEmpty()) {
382 mCallbacks.onAssistRequestCompleted();
383 }
384 }
385
Winson Chungda2818f2017-10-23 16:25:49 -0700386 public void dump(String prefix, PrintWriter pw) {
387 pw.print(prefix); pw.print("mPendingDataCount="); pw.println(mPendingDataCount);
388 pw.print(prefix); pw.print("mAssistData="); pw.println(mAssistData);
389 pw.print(prefix); pw.print("mPendingScreenshotCount="); pw.println(mPendingScreenshotCount);
390 pw.print(prefix); pw.print("mAssistScreenshot="); pw.println(mAssistScreenshot);
391 }
392}