blob: db216b1af974c9eae425efe407d9d30b7770512f [file] [log] [blame]
Aurimas Liutikasdc3f8852024-07-11 10:07:48 -07001/*
2 * Copyright (C) 2006 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 android.app;
18
19import android.annotation.FlaggedApi;
20import android.annotation.IntDef;
21import android.annotation.NonNull;
22import android.annotation.Nullable;
23import android.compat.annotation.UnsupportedAppUsage;
24import android.content.ActivityNotFoundException;
25import android.content.ComponentName;
26import android.content.Context;
27import android.content.Intent;
28import android.content.IntentFilter;
29import android.content.pm.ActivityInfo;
30import android.content.pm.PackageManager;
31import android.content.res.Configuration;
32import android.hardware.input.InputManager;
33import android.hardware.input.InputManagerGlobal;
34import android.net.Uri;
35import android.os.Build;
36import android.os.Bundle;
37import android.os.Debug;
38import android.os.IBinder;
39import android.os.Looper;
40import android.os.MessageQueue;
41import android.os.PerformanceCollector;
42import android.os.PersistableBundle;
43import android.os.Process;
44import android.os.RemoteException;
45import android.os.ServiceManager;
46import android.os.SystemClock;
47import android.os.SystemProperties;
48import android.os.TestLooperManager;
49import android.os.UserHandle;
50import android.os.UserManager;
51import android.util.AndroidRuntimeException;
52import android.util.Log;
53import android.view.Display;
54import android.view.IWindowManager;
55import android.view.InputDevice;
56import android.view.KeyCharacterMap;
57import android.view.KeyEvent;
58import android.view.MotionEvent;
59import android.view.SurfaceControl;
60import android.view.ViewConfiguration;
61import android.view.Window;
62import android.view.WindowManagerGlobal;
63
64import com.android.internal.content.ReferrerIntent;
65
66import java.io.File;
67import java.lang.annotation.Retention;
68import java.lang.annotation.RetentionPolicy;
69import java.util.ArrayList;
70import java.util.List;
71import java.util.Objects;
72import java.util.StringJoiner;
73import java.util.concurrent.TimeoutException;
74
75/**
76 * Base class for implementing application instrumentation code. When running
77 * with instrumentation turned on, this class will be instantiated for you
78 * before any of the application code, allowing you to monitor all of the
79 * interaction the system has with the application. An Instrumentation
80 * implementation is described to the system through an AndroidManifest.xml's
81 * <instrumentation> tag.
82 */
83@android.ravenwood.annotation.RavenwoodKeepPartialClass
84public class Instrumentation {
85
86 /**
87 * If included in the status or final bundle sent to an IInstrumentationWatcher, this key
88 * identifies the class that is writing the report. This can be used to provide more structured
89 * logging or reporting capabilities in the IInstrumentationWatcher.
90 */
91 public static final String REPORT_KEY_IDENTIFIER = "id";
92 /**
93 * If included in the status or final bundle sent to an IInstrumentationWatcher, this key
94 * identifies a string which can simply be printed to the output stream. Using these streams
95 * provides a "pretty printer" version of the status & final packets. Any bundles including
96 * this key should also include the complete set of raw key/value pairs, so that the
97 * instrumentation can also be launched, and results collected, by an automated system.
98 */
99 public static final String REPORT_KEY_STREAMRESULT = "stream";
100
101 private static final String TAG = "Instrumentation";
102
103 private static final long CONNECT_TIMEOUT_MILLIS = 60_000;
104
105 private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
106
107 // If set, will print the stack trace for activity starts within the process
108 static final boolean DEBUG_START_ACTIVITY = Build.IS_DEBUGGABLE &&
109 SystemProperties.getBoolean("persist.wm.debug.start_activity", false);
110
111 /**
112 * @hide
113 */
114 @Retention(RetentionPolicy.SOURCE)
115 @IntDef({0, UiAutomation.FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES,
116 UiAutomation.FLAG_DONT_USE_ACCESSIBILITY})
117 public @interface UiAutomationFlags {};
118
119
120 private final Object mSync = new Object();
121 private ActivityThread mThread = null;
122 private MessageQueue mMessageQueue = null;
123 private Context mInstrContext;
124 private Context mAppContext;
125 private ComponentName mComponent;
126 private Thread mRunner;
127 private List<ActivityWaiter> mWaitingActivities;
128 private List<ActivityMonitor> mActivityMonitors;
129 private IInstrumentationWatcher mWatcher;
130 private IUiAutomationConnection mUiAutomationConnection;
131 private boolean mAutomaticPerformanceSnapshots = false;
132 private PerformanceCollector mPerformanceCollector;
133 private Bundle mPerfMetrics = new Bundle();
134 private UiAutomation mUiAutomation;
135 private final Object mAnimationCompleteLock = new Object();
136
137 @android.ravenwood.annotation.RavenwoodKeep
138 public Instrumentation() {
139 }
140
141 /**
142 * Called for methods that shouldn't be called by standard apps and
143 * should only be used in instrumentation environments. This is not
144 * security feature as these classes will still be accessible through
145 * reflection, but it will serve as noticeable discouragement from
146 * doing such a thing.
147 */
148 @android.ravenwood.annotation.RavenwoodKeep
149 private void checkInstrumenting(String method) {
150 // Check if we have an instrumentation context, as init should only get called by
151 // the system in startup processes that are being instrumented.
152 if (mInstrContext == null) {
153 throw new RuntimeException(method +
154 " cannot be called outside of instrumented processes");
155 }
156 }
157
158 /**
159 * Returns if it is being called in an instrumentation environment.
160 *
161 * @hide
162 */
163 @android.ravenwood.annotation.RavenwoodKeep
164 public boolean isInstrumenting() {
165 // Check if we have an instrumentation context, as init should only get called by
166 // the system in startup processes that are being instrumented.
167 if (mInstrContext == null) {
168 return false;
169 }
170 return true;
171 }
172
173 /**
174 * Called when the instrumentation is starting, before any application code
175 * has been loaded. Usually this will be implemented to simply call
176 * {@link #start} to begin the instrumentation thread, which will then
177 * continue execution in {@link #onStart}.
178 *
179 * <p>If you do not need your own thread -- that is you are writing your
180 * instrumentation to be completely asynchronous (returning to the event
181 * loop so that the application can run), you can simply begin your
182 * instrumentation here, for example call {@link Context#startActivity} to
183 * begin the appropriate first activity of the application.
184 *
185 * @param arguments Any additional arguments that were supplied when the
186 * instrumentation was started.
187 */
188 public void onCreate(Bundle arguments) {
189 }
190
191 /**
192 * Create and start a new thread in which to run instrumentation. This new
193 * thread will call to {@link #onStart} where you can implement the
194 * instrumentation.
195 */
196 public void start() {
197 if (mRunner != null) {
198 throw new RuntimeException("Instrumentation already started");
199 }
200 mRunner = new InstrumentationThread("Instr: " + getClass().getName());
201 mRunner.start();
202 }
203
204 /**
205 * Method where the instrumentation thread enters execution. This allows
206 * you to run your instrumentation code in a separate thread than the
207 * application, so that it can perform blocking operation such as
208 * {@link #sendKeySync} or {@link #startActivitySync}.
209 *
210 * <p>You will typically want to call finish() when this function is done,
211 * to end your instrumentation.
212 */
213 public void onStart() {
214 }
215
216 /**
217 * This is called whenever the system captures an unhandled exception that
218 * was thrown by the application. The default implementation simply
219 * returns false, allowing normal system handling of the exception to take
220 * place.
221 *
222 * @param obj The client object that generated the exception. May be an
223 * Application, Activity, BroadcastReceiver, Service, or null.
224 * @param e The exception that was thrown.
225 *
226 * @return To allow normal system exception process to occur, return false.
227 * If true is returned, the system will proceed as if the exception
228 * didn't happen.
229 */
230 public boolean onException(Object obj, Throwable e) {
231 return false;
232 }
233
234 /**
235 * Provide a status report about the application.
236 *
237 * @param resultCode Current success/failure of instrumentation.
238 * @param results Any results to send back to the code that started the instrumentation.
239 */
240 public void sendStatus(int resultCode, Bundle results) {
241 if (mWatcher != null) {
242 try {
243 mWatcher.instrumentationStatus(mComponent, resultCode, results);
244 }
245 catch (RemoteException e) {
246 mWatcher = null;
247 }
248 }
249 }
250
251 /**
252 * Report some results in the middle of instrumentation execution. Later results (including
253 * those provided by {@link #finish}) will be combined with {@link Bundle#putAll}.
254 */
255 public void addResults(Bundle results) {
256 IActivityManager am = ActivityManager.getService();
257 try {
258 am.addInstrumentationResults(mThread.getApplicationThread(), results);
259 } catch (RemoteException ex) {
260 throw ex.rethrowFromSystemServer();
261 }
262 }
263
264 /**
265 * Terminate instrumentation of the application. This will cause the
266 * application process to exit, removing this instrumentation from the next
267 * time the application is started. If multiple processes are currently running
268 * for this instrumentation, all of those processes will be killed.
269 *
270 * @param resultCode Overall success/failure of instrumentation.
271 * @param results Any results to send back to the code that started the
272 * instrumentation.
273 */
274 public void finish(int resultCode, Bundle results) {
275 if (mAutomaticPerformanceSnapshots) {
276 endPerformanceSnapshot();
277 }
278 if (mPerfMetrics != null) {
279 if (results == null) {
280 results = new Bundle();
281 }
282 results.putAll(mPerfMetrics);
283 }
284 if ((mUiAutomation != null) && !mUiAutomation.isDestroyed()) {
285 mUiAutomation.disconnect();
286 mUiAutomation = null;
287 }
288 mThread.finishInstrumentation(resultCode, results);
289 }
290
291 public void setAutomaticPerformanceSnapshots() {
292 mAutomaticPerformanceSnapshots = true;
293 mPerformanceCollector = new PerformanceCollector();
294 }
295
296 public void startPerformanceSnapshot() {
297 if (!isProfiling()) {
298 mPerformanceCollector.beginSnapshot(null);
299 }
300 }
301
302 public void endPerformanceSnapshot() {
303 if (!isProfiling()) {
304 mPerfMetrics = mPerformanceCollector.endSnapshot();
305 }
306 }
307
308 /**
309 * Called when the instrumented application is stopping, after all of the
310 * normal application cleanup has occurred.
311 */
312 public void onDestroy() {
313 }
314
315 /**
316 * Return the Context of this instrumentation's package. Note that this is
317 * often different than the Context of the application being
318 * instrumentated, since the instrumentation code often lives is a
319 * different package than that of the application it is running against.
320 * See {@link #getTargetContext} to retrieve a Context for the target
321 * application.
322 *
323 * @return The instrumentation's package context.
324 *
325 * @see #getTargetContext
326 */
327 @android.ravenwood.annotation.RavenwoodKeep
328 public Context getContext() {
329 return mInstrContext;
330 }
331
332 /**
333 * Returns complete component name of this instrumentation.
334 *
335 * @return Returns the complete component name for this instrumentation.
336 */
337 public ComponentName getComponentName() {
338 return mComponent;
339 }
340
341 /**
342 * Return a Context for the target application being instrumented. Note
343 * that this is often different than the Context of the instrumentation
344 * code, since the instrumentation code often lives is a different package
345 * than that of the application it is running against. See
346 * {@link #getContext} to retrieve a Context for the instrumentation code.
347 *
348 * @return A Context in the target application.
349 *
350 * @see #getContext
351 */
352 @android.ravenwood.annotation.RavenwoodKeep
353 public Context getTargetContext() {
354 return mAppContext;
355 }
356
357 /**
358 * Return the name of the process this instrumentation is running in. Note this should
359 * only be used for testing and debugging. If you are thinking about using this to,
360 * for example, conditionalize what is initialized in an Application class, it is strongly
361 * recommended to instead use lazy initialization (such as a getter for the state that
362 * only creates it when requested). This can greatly reduce the work your process does
363 * when created for secondary things, such as to receive a broadcast.
364 */
365 public String getProcessName() {
366 return mThread.getProcessName();
367 }
368
369 /**
370 * Check whether this instrumentation was started with profiling enabled.
371 *
372 * @return Returns true if profiling was enabled when starting, else false.
373 */
374 public boolean isProfiling() {
375 return mThread.isProfiling();
376 }
377
378 /**
379 * This method will start profiling if isProfiling() returns true. You should
380 * only call this method if you set the handleProfiling attribute in the
381 * manifest file for this Instrumentation to true.
382 */
383 public void startProfiling() {
384 if (mThread.isProfiling()) {
385 File file = new File(mThread.getProfileFilePath());
386 file.getParentFile().mkdirs();
387 Debug.startMethodTracing(file.toString(), 8 * 1024 * 1024);
388 }
389 }
390
391 /**
392 * Stops profiling if isProfiling() returns true.
393 */
394 public void stopProfiling() {
395 if (mThread.isProfiling()) {
396 Debug.stopMethodTracing();
397 }
398 }
399
400 /**
401 * Force the global system in or out of touch mode. This can be used if your
402 * instrumentation relies on the UI being in one more or the other when it starts.
403 *
404 * <p><b>Note:</b> Starting from Android {@link Build.VERSION_CODES#TIRAMISU}, this method
405 * will only take effect if the instrumentation was sourced from a process with
406 * {@code MODIFY_TOUCH_MODE_STATE} internal permission granted (shell already have it).
407 *
408 * @param inTouch Set to true to be in touch mode, false to be in focus mode.
409 */
410 public void setInTouchMode(boolean inTouch) {
411 try {
412 IWindowManager.Stub.asInterface(
413 ServiceManager.getService("window")).setInTouchModeOnAllDisplays(inTouch);
414 } catch (RemoteException e) {
415 // Shouldn't happen!
416 }
417 }
418
419 /**
420 * Resets the {@link #setInTouchMode touch mode} to the device default.
421 */
422 public void resetInTouchMode() {
423 final boolean defaultInTouchMode = getContext().getResources().getBoolean(
424 com.android.internal.R.bool.config_defaultInTouchMode);
425 setInTouchMode(defaultInTouchMode);
426 }
427
428 /**
429 * Schedule a callback for when the application's main thread goes idle
430 * (has no more events to process).
431 *
432 * @param recipient Called the next time the thread's message queue is
433 * idle.
434 */
435 public void waitForIdle(Runnable recipient) {
436 mMessageQueue.addIdleHandler(new Idler(recipient));
437 mThread.getHandler().post(new EmptyRunnable());
438 }
439
440 /**
441 * Synchronously wait for the application to be idle. Can not be called
442 * from the main application thread -- use {@link #start} to execute
443 * instrumentation in its own thread.
444 */
445 public void waitForIdleSync() {
446 validateNotAppThread();
447 Idler idler = new Idler(null);
448 mMessageQueue.addIdleHandler(idler);
449 mThread.getHandler().post(new EmptyRunnable());
450 idler.waitForIdle();
451 }
452
453 private void waitForEnterAnimationComplete(Activity activity) {
454 synchronized (mAnimationCompleteLock) {
455 long timeout = 5000;
456 try {
457 // We need to check that this specified Activity completed the animation, not just
458 // any Activity. If it was another Activity, then decrease the timeout by how long
459 // it's already waited and wait for the thread to wakeup again.
460 while (timeout > 0 && !activity.mEnterAnimationComplete) {
461 long startTime = System.currentTimeMillis();
462 mAnimationCompleteLock.wait(timeout);
463 long totalTime = System.currentTimeMillis() - startTime;
464 timeout -= totalTime;
465 }
466 } catch (InterruptedException e) {
467 }
468 }
469 }
470
471 /** @hide */
472 public void onEnterAnimationComplete() {
473 synchronized (mAnimationCompleteLock) {
474 mAnimationCompleteLock.notifyAll();
475 }
476 }
477
478 /**
479 * Execute a call on the application's main thread, blocking until it is
480 * complete. Useful for doing things that are not thread-safe, such as
481 * looking at or modifying the view hierarchy.
482 *
483 * @param runner The code to run on the main thread.
484 */
485 public void runOnMainSync(Runnable runner) {
486 validateNotAppThread();
487 SyncRunnable sr = new SyncRunnable(runner);
488 mThread.getHandler().post(sr);
489 sr.waitForComplete();
490 }
491
492 boolean isSdkSandboxAllowedToStartActivities() {
493 return Process.isSdkSandbox()
494 && mThread != null
495 && mThread.mBoundApplication != null
496 && mThread.mBoundApplication.isSdkInSandbox
497 && getContext() != null
498 && (getContext()
499 .checkSelfPermission(
500 android.Manifest.permission
501 .START_ACTIVITIES_FROM_SDK_SANDBOX)
502 == PackageManager.PERMISSION_GRANTED);
503 }
504
505 /**
506 * Activity name resolution for CTS-in-SdkSandbox tests requires some adjustments. Intents
507 * generated using {@link Context#getPackageName()} use the SDK sandbox package name in the
508 * component field instead of the test package name. An SDK-in-sandbox test attempting to launch
509 * an activity in the test package will encounter name resolution errors when resolving the
510 * activity name in the SDK sandbox package.
511 *
512 * <p>This function replaces the package name of the input intent component to allow activities
513 * belonging to a CTS-in-sandbox test to resolve correctly.
514 *
515 * @param intent the intent to modify to allow CTS-in-sandbox activity resolution.
516 */
517 private void adjustIntentForCtsInSdkSandboxInstrumentation(@NonNull Intent intent) {
518 if (mComponent != null
519 && intent.getComponent() != null
520 && getContext()
521 .getPackageManager()
522 .getSdkSandboxPackageName()
523 .equals(intent.getComponent().getPackageName())) {
524 // Resolve the intent target for the test package, not for the sandbox package.
525 intent.setComponent(
526 new ComponentName(
527 mComponent.getPackageName(), intent.getComponent().getClassName()));
528 }
529 // We match the intent identifier against the running instrumentations for the sandbox.
530 intent.setIdentifier(mComponent.getPackageName());
531 }
532
533 private ActivityInfo resolveActivityInfoForCtsInSandbox(@NonNull Intent intent) {
534 adjustIntentForCtsInSdkSandboxInstrumentation(intent);
535 ActivityInfo ai = intent.resolveActivityInfo(getTargetContext().getPackageManager(), 0);
536 if (ai != null) {
537 ai.processName = mThread.getProcessName();
538 }
539 return ai;
540 }
541
542 /**
543 * Start a new activity and wait for it to begin running before returning.
544 * In addition to being synchronous, this method as some semantic
545 * differences from the standard {@link Context#startActivity} call: the
546 * activity component is resolved before talking with the activity manager
547 * (its class name is specified in the Intent that this method ultimately
548 * starts), and it does not allow you to start activities that run in a
549 * different process. In addition, if the given Intent resolves to
550 * multiple activities, instead of displaying a dialog for the user to
551 * select an activity, an exception will be thrown.
552 *
553 * <p>The function returns as soon as the activity goes idle following the
554 * call to its {@link Activity#onCreate}. Generally this means it has gone
555 * through the full initialization including {@link Activity#onResume} and
556 * drawn and displayed its initial window.
557 *
558 * @param intent Description of the activity to start.
559 *
560 * @see Context#startActivity
561 * @see #startActivitySync(Intent, Bundle)
562 */
563 public Activity startActivitySync(Intent intent) {
564 return startActivitySync(intent, null /* options */);
565 }
566
567 /**
568 * Start a new activity and wait for it to begin running before returning.
569 * In addition to being synchronous, this method as some semantic
570 * differences from the standard {@link Context#startActivity} call: the
571 * activity component is resolved before talking with the activity manager
572 * (its class name is specified in the Intent that this method ultimately
573 * starts), and it does not allow you to start activities that run in a
574 * different process. In addition, if the given Intent resolves to
575 * multiple activities, instead of displaying a dialog for the user to
576 * select an activity, an exception will be thrown.
577 *
578 * <p>The function returns as soon as the activity goes idle following the
579 * call to its {@link Activity#onCreate}. Generally this means it has gone
580 * through the full initialization including {@link Activity#onResume} and
581 * drawn and displayed its initial window.
582 *
583 * @param intent Description of the activity to start.
584 * @param options Additional options for how the Activity should be started.
585 * May be null if there are no options. See {@link android.app.ActivityOptions}
586 * for how to build the Bundle supplied here; there are no supported definitions
587 * for building it manually.
588 *
589 * @see Context#startActivity(Intent, Bundle)
590 */
591 @NonNull
592 public Activity startActivitySync(@NonNull Intent intent, @Nullable Bundle options) {
593 if (DEBUG_START_ACTIVITY) {
594 Log.d(TAG, "startActivity: intent=" + intent + " options=" + options, new Throwable());
595 }
596 validateNotAppThread();
597
598 final Activity activity;
599 synchronized (mSync) {
600 intent = new Intent(intent);
601
602 ActivityInfo ai =
603 isSdkSandboxAllowedToStartActivities()
604 ? resolveActivityInfoForCtsInSandbox(intent)
605 : intent.resolveActivityInfo(getTargetContext().getPackageManager(), 0);
606 if (ai == null) {
607 throw new RuntimeException("Unable to resolve activity for: " + intent);
608 }
609 String myProc = mThread.getProcessName();
610 if (!ai.processName.equals(myProc)) {
611 // todo: if this intent is ambiguous, look here to see if
612 // there is a single match that is in our package.
613 throw new RuntimeException("Intent in process "
614 + myProc + " resolved to different process "
615 + ai.processName + ": " + intent);
616 }
617
618 intent.setComponent(new ComponentName(
619 ai.applicationInfo.packageName, ai.name));
620 final ActivityWaiter aw = new ActivityWaiter(intent);
621
622 if (mWaitingActivities == null) {
623 mWaitingActivities = new ArrayList();
624 }
625 mWaitingActivities.add(aw);
626
627 getTargetContext().startActivity(intent, options);
628
629 do {
630 try {
631 mSync.wait();
632 } catch (InterruptedException e) {
633 }
634 } while (mWaitingActivities.contains(aw));
635 activity = aw.activity;
636 }
637
638 // Do not call this method within mSync, lest it could block the main thread.
639 waitForEnterAnimationComplete(activity);
640
641 // Apply an empty transaction to ensure SF has a chance to update before
642 // the Activity is ready (b/138263890).
643 try (SurfaceControl.Transaction t = new SurfaceControl.Transaction()) {
644 t.apply(true);
645 }
646 return activity;
647 }
648
649 /**
650 * Information about a particular kind of Intent that is being monitored.
651 * An instance of this class is added to the
652 * current instrumentation through {@link #addMonitor}; after being added,
653 * when a new activity is being started the monitor will be checked and, if
654 * matching, its hit count updated and (optionally) the call stopped and a
655 * canned result returned.
656 *
657 * <p>An ActivityMonitor can also be used to look for the creation of an
658 * activity, through the {@link #waitForActivity} method. This will return
659 * after a matching activity has been created with that activity object.
660 */
661 public static class ActivityMonitor {
662 private final IntentFilter mWhich;
663 private final String mClass;
664 private final ActivityResult mResult;
665 private final boolean mBlock;
666 private final boolean mIgnoreMatchingSpecificIntents;
667
668
669 // This is protected by 'Instrumentation.this.mSync'.
670 /*package*/ int mHits = 0;
671
672 // This is protected by 'this'.
673 /*package*/ Activity mLastActivity = null;
674
675 /**
676 * Create a new ActivityMonitor that looks for a particular kind of
677 * intent to be started.
678 *
679 * @param which The set of intents this monitor is responsible for.
680 * @param result A canned result to return if the monitor is hit; can
681 * be null.
682 * @param block Controls whether the monitor should block the activity
683 * start (returning its canned result) or let the call
684 * proceed.
685 *
686 * @see Instrumentation#addMonitor
687 */
688 public ActivityMonitor(
689 IntentFilter which, ActivityResult result, boolean block) {
690 mWhich = which;
691 mClass = null;
692 mResult = result;
693 mBlock = block;
694 mIgnoreMatchingSpecificIntents = false;
695 }
696
697 /**
698 * Create a new ActivityMonitor that looks for a specific activity
699 * class to be started.
700 *
701 * @param cls The activity class this monitor is responsible for.
702 * @param result A canned result to return if the monitor is hit; can
703 * be null.
704 * @param block Controls whether the monitor should block the activity
705 * start (returning its canned result) or let the call
706 * proceed.
707 *
708 * @see Instrumentation#addMonitor
709 */
710 public ActivityMonitor(
711 String cls, ActivityResult result, boolean block) {
712 mWhich = null;
713 mClass = cls;
714 mResult = result;
715 mBlock = block;
716 mIgnoreMatchingSpecificIntents = false;
717 }
718
719 /**
720 * Create a new ActivityMonitor that can be used for intercepting any activity to be
721 * started.
722 *
723 * <p> When an activity is started, {@link #onStartActivity(Intent)} will be called on
724 * instances created using this constructor to see if it is a hit.
725 *
726 * @see #onStartActivity(Intent)
727 */
728 public ActivityMonitor() {
729 mWhich = null;
730 mClass = null;
731 mResult = null;
732 mBlock = false;
733 mIgnoreMatchingSpecificIntents = true;
734 }
735
736 /**
737 * @return true if this monitor is used for intercepting any started activity by calling
738 * into {@link #onStartActivity(Intent)}, false if this monitor is only used
739 * for specific intents corresponding to the intent filter or activity class
740 * passed in the constructor.
741 */
742 final boolean ignoreMatchingSpecificIntents() {
743 return mIgnoreMatchingSpecificIntents;
744 }
745
746 /**
747 * Retrieve the filter associated with this ActivityMonitor.
748 */
749 public final IntentFilter getFilter() {
750 return mWhich;
751 }
752
753 /**
754 * Retrieve the result associated with this ActivityMonitor, or null if
755 * none.
756 */
757 public final ActivityResult getResult() {
758 return mResult;
759 }
760
761 /**
762 * Check whether this monitor blocks activity starts (not allowing the
763 * actual activity to run) or allows them to execute normally.
764 */
765 public final boolean isBlocking() {
766 return mBlock;
767 }
768
769 /**
770 * Retrieve the number of times the monitor has been hit so far.
771 */
772 public final int getHits() {
773 return mHits;
774 }
775
776 /**
777 * Retrieve the most recent activity class that was seen by this
778 * monitor.
779 */
780 public final Activity getLastActivity() {
781 return mLastActivity;
782 }
783
784 /**
785 * Block until an Activity is created that matches this monitor,
786 * returning the resulting activity.
787 *
788 * @return Activity
789 */
790 public final Activity waitForActivity() {
791 synchronized (this) {
792 while (mLastActivity == null) {
793 try {
794 wait();
795 } catch (InterruptedException e) {
796 }
797 }
798 Activity res = mLastActivity;
799 mLastActivity = null;
800 return res;
801 }
802 }
803
804 /**
805 * Block until an Activity is created that matches this monitor,
806 * returning the resulting activity or till the timeOut period expires.
807 * If the timeOut expires before the activity is started, return null.
808 *
809 * @param timeOut Time to wait in milliseconds before the activity is created.
810 *
811 * @return Activity
812 */
813 public final Activity waitForActivityWithTimeout(long timeOut) {
814 synchronized (this) {
815 if (mLastActivity == null) {
816 try {
817 wait(timeOut);
818 } catch (InterruptedException e) {
819 }
820 }
821 if (mLastActivity == null) {
822 return null;
823 } else {
824 Activity res = mLastActivity;
825 mLastActivity = null;
826 return res;
827 }
828 }
829 }
830
831 /**
832 * This overload is used for notifying the {@link android.window.TaskFragmentOrganizer}
833 * implementation internally about started activities.
834 *
835 * @see #onStartActivity(Intent)
836 * @hide
837 */
838 public ActivityResult onStartActivity(@NonNull Context who, @NonNull Intent intent,
839 @NonNull Bundle options) {
840 return onStartActivity(intent);
841 }
842
843 /**
844 * Used for intercepting any started activity.
845 *
846 * <p> A non-null return value here will be considered a hit for this monitor.
847 * By default this will return {@code null} and subclasses can override this to return
848 * a non-null value if the intent needs to be intercepted.
849 *
850 * <p> Whenever a new activity is started, this method will be called on instances created
851 * using {@link #ActivityMonitor()} to check if there is a match. In case
852 * of a match, the activity start will be blocked and the returned result will be used.
853 *
854 * @param intent The intent used for starting the activity.
855 * @return The {@link ActivityResult} that needs to be used in case of a match.
856 */
857 public ActivityResult onStartActivity(Intent intent) {
858 return null;
859 }
860
861 /**
862 * This is called after starting an Activity and provides the result code that defined in
863 * {@link ActivityManager}, like {@link ActivityManager#START_SUCCESS}.
864 *
865 * @param result the result code that returns after starting an Activity.
866 * @param bOptions the bundle generated from {@link ActivityOptions} that originally
867 * being used to start the Activity.
868 * @hide
869 */
870 public void onStartActivityResult(int result, @NonNull Bundle bOptions) {}
871
872 final boolean match(Context who,
873 Activity activity,
874 Intent intent) {
875 if (mIgnoreMatchingSpecificIntents) {
876 return false;
877 }
878 synchronized (this) {
879 if (mWhich != null
880 && mWhich.match(who.getContentResolver(), intent,
881 true, "Instrumentation") < 0) {
882 return false;
883 }
884 if (mClass != null) {
885 String cls = null;
886 if (activity != null) {
887 cls = activity.getClass().getName();
888 } else if (intent.getComponent() != null) {
889 cls = intent.getComponent().getClassName();
890 }
891 if (cls == null || !mClass.equals(cls)) {
892 return false;
893 }
894 }
895 if (activity != null) {
896 mLastActivity = activity;
897 notifyAll();
898 }
899 return true;
900 }
901 }
902 }
903
904 /**
905 * Add a new {@link ActivityMonitor} that will be checked whenever an
906 * activity is started. The monitor is added
907 * after any existing ones; the monitor will be hit only if none of the
908 * existing monitors can themselves handle the Intent.
909 *
910 * @param monitor The new ActivityMonitor to see.
911 *
912 * @see #addMonitor(IntentFilter, ActivityResult, boolean)
913 * @see #checkMonitorHit
914 */
915 public void addMonitor(ActivityMonitor monitor) {
916 synchronized (mSync) {
917 if (mActivityMonitors == null) {
918 mActivityMonitors = new ArrayList();
919 }
920 mActivityMonitors.add(monitor);
921 }
922 }
923
924 /**
925 * A convenience wrapper for {@link #addMonitor(ActivityMonitor)} that
926 * creates an intent filter matching {@link ActivityMonitor} for you and
927 * returns it.
928 *
929 * @param filter The set of intents this monitor is responsible for.
930 * @param result A canned result to return if the monitor is hit; can
931 * be null.
932 * @param block Controls whether the monitor should block the activity
933 * start (returning its canned result) or let the call
934 * proceed.
935 *
936 * @return The newly created and added activity monitor.
937 *
938 * @see #addMonitor(ActivityMonitor)
939 * @see #checkMonitorHit
940 */
941 public ActivityMonitor addMonitor(
942 IntentFilter filter, ActivityResult result, boolean block) {
943 ActivityMonitor am = new ActivityMonitor(filter, result, block);
944 addMonitor(am);
945 return am;
946 }
947
948 /**
949 * A convenience wrapper for {@link #addMonitor(ActivityMonitor)} that
950 * creates a class matching {@link ActivityMonitor} for you and returns it.
951 *
952 * @param cls The activity class this monitor is responsible for.
953 * @param result A canned result to return if the monitor is hit; can
954 * be null.
955 * @param block Controls whether the monitor should block the activity
956 * start (returning its canned result) or let the call
957 * proceed.
958 *
959 * @return The newly created and added activity monitor.
960 *
961 * @see #addMonitor(ActivityMonitor)
962 * @see #checkMonitorHit
963 */
964 public ActivityMonitor addMonitor(
965 String cls, ActivityResult result, boolean block) {
966 ActivityMonitor am = new ActivityMonitor(cls, result, block);
967 addMonitor(am);
968 return am;
969 }
970
971 /**
972 * Test whether an existing {@link ActivityMonitor} has been hit. If the
973 * monitor has been hit at least <var>minHits</var> times, then it will be
974 * removed from the activity monitor list and true returned. Otherwise it
975 * is left as-is and false is returned.
976 *
977 * @param monitor The ActivityMonitor to check.
978 * @param minHits The minimum number of hits required.
979 *
980 * @return True if the hit count has been reached, else false.
981 *
982 * @see #addMonitor
983 */
984 public boolean checkMonitorHit(ActivityMonitor monitor, int minHits) {
985 waitForIdleSync();
986 synchronized (mSync) {
987 if (monitor.getHits() < minHits) {
988 return false;
989 }
990 mActivityMonitors.remove(monitor);
991 }
992 return true;
993 }
994
995 /**
996 * Wait for an existing {@link ActivityMonitor} to be hit. Once the
997 * monitor has been hit, it is removed from the activity monitor list and
998 * the first created Activity object that matched it is returned.
999 *
1000 * @param monitor The ActivityMonitor to wait for.
1001 *
1002 * @return The Activity object that matched the monitor.
1003 */
1004 public Activity waitForMonitor(ActivityMonitor monitor) {
1005 Activity activity = monitor.waitForActivity();
1006 synchronized (mSync) {
1007 mActivityMonitors.remove(monitor);
1008 }
1009 return activity;
1010 }
1011
1012 /**
1013 * Wait for an existing {@link ActivityMonitor} to be hit till the timeout
1014 * expires. Once the monitor has been hit, it is removed from the activity
1015 * monitor list and the first created Activity object that matched it is
1016 * returned. If the timeout expires, a null object is returned.
1017 *
1018 * @param monitor The ActivityMonitor to wait for.
1019 * @param timeOut The timeout value in milliseconds.
1020 *
1021 * @return The Activity object that matched the monitor.
1022 */
1023 public Activity waitForMonitorWithTimeout(ActivityMonitor monitor, long timeOut) {
1024 Activity activity = monitor.waitForActivityWithTimeout(timeOut);
1025 synchronized (mSync) {
1026 mActivityMonitors.remove(monitor);
1027 }
1028 return activity;
1029 }
1030
1031 /**
1032 * Remove an {@link ActivityMonitor} that was previously added with
1033 * {@link #addMonitor}.
1034 *
1035 * @param monitor The monitor to remove.
1036 *
1037 * @see #addMonitor
1038 */
1039 public void removeMonitor(ActivityMonitor monitor) {
1040 synchronized (mSync) {
1041 mActivityMonitors.remove(monitor);
1042 }
1043 }
1044
1045 /**
1046 * Execute a particular menu item.
1047 *
1048 * @param targetActivity The activity in question.
1049 * @param id The identifier associated with the menu item.
1050 * @param flag Additional flags, if any.
1051 * @return Whether the invocation was successful (for example, it could be
1052 * false if item is disabled).
1053 */
1054 public boolean invokeMenuActionSync(Activity targetActivity,
1055 int id, int flag) {
1056 class MenuRunnable implements Runnable {
1057 private final Activity activity;
1058 private final int identifier;
1059 private final int flags;
1060 boolean returnValue;
1061
1062 public MenuRunnable(Activity _activity, int _identifier,
1063 int _flags) {
1064 activity = _activity;
1065 identifier = _identifier;
1066 flags = _flags;
1067 }
1068
1069 public void run() {
1070 Window win = activity.getWindow();
1071
1072 returnValue = win.performPanelIdentifierAction(
1073 Window.FEATURE_OPTIONS_PANEL,
1074 identifier,
1075 flags);
1076 }
1077
1078 }
1079 MenuRunnable mr = new MenuRunnable(targetActivity, id, flag);
1080 runOnMainSync(mr);
1081 return mr.returnValue;
1082 }
1083
1084 /**
1085 * Show the context menu for the currently focused view and executes a
1086 * particular context menu item.
1087 *
1088 * @param targetActivity The activity in question.
1089 * @param id The identifier associated with the context menu item.
1090 * @param flag Additional flags, if any.
1091 * @return Whether the invocation was successful (for example, it could be
1092 * false if item is disabled).
1093 */
1094 public boolean invokeContextMenuAction(Activity targetActivity, int id, int flag) {
1095 validateNotAppThread();
1096
1097 // Bring up context menu for current focus.
1098 // It'd be nice to do this through code, but currently ListView depends on
1099 // long press to set metadata for its selected child
1100
1101 final KeyEvent downEvent = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_CENTER);
1102 sendKeySync(downEvent);
1103
1104 // Need to wait for long press
1105 waitForIdleSync();
1106 try {
1107 Thread.sleep(ViewConfiguration.getLongPressTimeout());
1108 } catch (InterruptedException e) {
1109 Log.e(TAG, "Could not sleep for long press timeout", e);
1110 return false;
1111 }
1112
1113 final KeyEvent upEvent = new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DPAD_CENTER);
1114 sendKeySync(upEvent);
1115
1116 // Wait for context menu to appear
1117 waitForIdleSync();
1118
1119 class ContextMenuRunnable implements Runnable {
1120 private final Activity activity;
1121 private final int identifier;
1122 private final int flags;
1123 boolean returnValue;
1124
1125 public ContextMenuRunnable(Activity _activity, int _identifier,
1126 int _flags) {
1127 activity = _activity;
1128 identifier = _identifier;
1129 flags = _flags;
1130 }
1131
1132 public void run() {
1133 Window win = activity.getWindow();
1134 returnValue = win.performContextMenuIdentifierAction(
1135 identifier,
1136 flags);
1137 }
1138
1139 }
1140
1141 ContextMenuRunnable cmr = new ContextMenuRunnable(targetActivity, id, flag);
1142 runOnMainSync(cmr);
1143 return cmr.returnValue;
1144 }
1145
1146 /**
1147 * Sends the key events that result in the given text being typed into the currently focused
1148 * window, and waits for it to be processed.
1149 *
1150 * @param text The text to be sent.
1151 * @see #sendKeySync(KeyEvent)
1152 */
1153 public void sendStringSync(String text) {
1154 if (text == null) {
1155 return;
1156 }
1157 KeyCharacterMap keyCharacterMap = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD);
1158
1159 KeyEvent[] events = keyCharacterMap.getEvents(text.toCharArray());
1160
1161 if (events != null) {
1162 for (int i = 0; i < events.length; i++) {
1163 // We have to change the time of an event before injecting it because
1164 // all KeyEvents returned by KeyCharacterMap.getEvents() have the same
1165 // time stamp and the system rejects too old events. Hence, it is
1166 // possible for an event to become stale before it is injected if it
1167 // takes too long to inject the preceding ones.
1168 sendKeySync(KeyEvent.changeTimeRepeat(events[i], SystemClock.uptimeMillis(), 0));
1169 }
1170 }
1171 }
1172
1173 /**
1174 * Sends a key event to the currently focused window, and waits for it to be processed.
1175 * <p>
1176 * This method blocks until the recipient has finished handling the event. Note that the
1177 * recipient may <em>not</em> have completely finished reacting from the event when this method
1178 * returns. For example, it may still be in the process of updating its display or UI contents
1179 * upon reacting to the injected event.
1180 *
1181 * @param event The event to send to the current focus.
1182 */
1183 public void sendKeySync(KeyEvent event) {
1184 validateNotAppThread();
1185
1186 long downTime = event.getDownTime();
1187 long eventTime = event.getEventTime();
1188 int source = event.getSource();
1189 if (source == InputDevice.SOURCE_UNKNOWN) {
1190 source = InputDevice.SOURCE_KEYBOARD;
1191 }
1192 if (eventTime == 0) {
1193 eventTime = SystemClock.uptimeMillis();
1194 }
1195 if (downTime == 0) {
1196 downTime = eventTime;
1197 }
1198 KeyEvent newEvent = new KeyEvent(event);
1199 newEvent.setTime(downTime, eventTime);
1200 newEvent.setSource(source);
1201 newEvent.setFlags(event.getFlags() | KeyEvent.FLAG_FROM_SYSTEM);
1202 setDisplayIfNeeded(newEvent);
1203
1204 InputManagerGlobal.getInstance().injectInputEvent(newEvent,
1205 InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH);
1206 }
1207
1208 private void setDisplayIfNeeded(KeyEvent event) {
1209 if (!UserManager.isVisibleBackgroundUsersEnabled()) {
1210 return;
1211 }
1212 // In devices that support visible background users visible, the display id must be set to
1213 // reflect the display the user was started visible on, otherwise the event would be sent to
1214 // the main display (which would most likely fail the test).
1215 int eventDisplayId = event.getDisplayId();
1216 if (eventDisplayId != Display.INVALID_DISPLAY) {
1217 if (VERBOSE) {
1218 Log.v(TAG, "setDisplayIfNeeded(" + event + "): not changing display id as it's "
1219 + "explicitly set to " + eventDisplayId);
1220 }
1221 return;
1222 }
1223
1224 UserManager userManager = mInstrContext.getSystemService(UserManager.class);
1225 int userDisplayId = userManager.getMainDisplayIdAssignedToUser();
1226 if (VERBOSE) {
1227 Log.v(TAG, "setDisplayIfNeeded(" + event + "): eventDisplayId=" + eventDisplayId
1228 + ", user=" + mInstrContext.getUser() + ", userDisplayId=" + userDisplayId);
1229 }
1230 if (userDisplayId == Display.INVALID_DISPLAY) {
1231 Log.e(TAG, "setDisplayIfNeeded(" + event + "): UserManager returned INVALID_DISPLAY as "
1232 + "display assigned to user " + mInstrContext.getUser());
1233 return;
1234
1235 }
1236
1237 event.setDisplayId(userDisplayId);
1238 }
1239
1240 /**
1241 * Sends up and down key events with the given key code to the currently focused window, and
1242 * waits for it to be processed.
1243 *
1244 * @param keyCode The key code for the events to send.
1245 * @see #sendKeySync(KeyEvent)
1246 */
1247 public void sendKeyDownUpSync(int keyCode) {
1248 sendKeySync(new KeyEvent(KeyEvent.ACTION_DOWN, keyCode));
1249 sendKeySync(new KeyEvent(KeyEvent.ACTION_UP, keyCode));
1250 }
1251
1252 /**
1253 * Sends up and down key events with the given key code to the currently focused window, and
1254 * waits for it to be processed.
1255 * <p>
1256 * Equivalent to {@link #sendKeyDownUpSync(int)}.
1257 *
1258 * @param keyCode The key code of the character to send.
1259 * @see #sendKeySync(KeyEvent)
1260 */
1261 public void sendCharacterSync(int keyCode) {
1262 sendKeyDownUpSync(keyCode);
1263 }
1264
1265 /**
1266 * Dispatches a pointer event into a window owned by the instrumented application, and waits for
1267 * it to be processed.
1268 * <p>
1269 * If the motion event being injected is targeted at a window that is not owned by the
1270 * instrumented application, the input injection will fail. See {@link #getUiAutomation()} for
1271 * injecting events into all windows.
1272 * <p>
1273 * This method blocks until the recipient has finished handling the event. Note that the
1274 * recipient may <em>not</em> have completely finished reacting from the event when this method
1275 * returns. For example, it may still be in the process of updating its display or UI contents
1276 * upon reacting to the injected event.
1277 *
1278 * @param event A motion event describing the pointer action. (As noted in
1279 * {@link MotionEvent#obtain(long, long, int, float, float, int)}, be sure to use
1280 * {@link SystemClock#uptimeMillis()} as the timebase.
1281 */
1282 public void sendPointerSync(MotionEvent event) {
1283 validateNotAppThread();
1284 if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) == 0) {
1285 event.setSource(InputDevice.SOURCE_TOUCHSCREEN);
1286 }
1287
1288 syncInputTransactionsAndInjectEventIntoSelf(event);
1289 }
1290
1291 private void syncInputTransactionsAndInjectEventIntoSelf(MotionEvent event) {
1292 final boolean syncBefore = event.getAction() == MotionEvent.ACTION_DOWN
1293 || event.isFromSource(InputDevice.SOURCE_MOUSE);
1294 final boolean syncAfter = event.getAction() == MotionEvent.ACTION_UP;
1295
1296 try {
1297 if (syncBefore) {
1298 WindowManagerGlobal.getWindowManagerService()
1299 .syncInputTransactions(true /*waitForAnimations*/);
1300 }
1301
1302 // Direct the injected event into windows owned by the instrumentation target.
1303 InputManagerGlobal.getInstance().injectInputEvent(
1304 event, InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH, Process.myUid());
1305
1306 if (syncAfter) {
1307 WindowManagerGlobal.getWindowManagerService()
1308 .syncInputTransactions(true /*waitForAnimations*/);
1309 }
1310 } catch (RemoteException e) {
1311 e.rethrowFromSystemServer();
1312 }
1313 }
1314
1315 /**
1316 * Dispatches a trackball event into the currently focused window, and waits for it to be
1317 * processed.
1318 * <p>
1319 * This method blocks until the recipient has finished handling the event. Note that the
1320 * recipient may <em>not</em> have completely finished reacting from the event when this method
1321 * returns. For example, it may still be in the process of updating its display or UI contents
1322 * upon reacting to the injected event.
1323 *
1324 * @param event A motion event describing the trackball action. (As noted in
1325 * {@link MotionEvent#obtain(long, long, int, float, float, int)}, be sure to use
1326 * {@link SystemClock#uptimeMillis()} as the timebase.
1327 */
1328 public void sendTrackballEventSync(MotionEvent event) {
1329 validateNotAppThread();
1330 if (!event.isFromSource(InputDevice.SOURCE_CLASS_TRACKBALL)) {
1331 event.setSource(InputDevice.SOURCE_TRACKBALL);
1332 }
1333 InputManagerGlobal.getInstance().injectInputEvent(event,
1334 InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH);
1335 }
1336
1337 /**
1338 * Perform instantiation of the process's {@link Application} object. The
1339 * default implementation provides the normal system behavior.
1340 *
1341 * @param cl The ClassLoader with which to instantiate the object.
1342 * @param className The name of the class implementing the Application
1343 * object.
1344 * @param context The context to initialize the application with
1345 *
1346 * @return The newly instantiated Application object.
1347 */
1348 public Application newApplication(ClassLoader cl, String className, Context context)
1349 throws InstantiationException, IllegalAccessException,
1350 ClassNotFoundException {
1351 Application app = getFactory(context.getPackageName())
1352 .instantiateApplication(cl, className);
1353 app.attach(context);
1354 return app;
1355 }
1356
1357 /**
1358 * Perform instantiation of the process's {@link Application} object. The
1359 * default implementation provides the normal system behavior.
1360 *
1361 * @param clazz The class used to create an Application object from.
1362 * @param context The context to initialize the application with
1363 *
1364 * @return The newly instantiated Application object.
1365 */
1366 static public Application newApplication(Class<?> clazz, Context context)
1367 throws InstantiationException, IllegalAccessException,
1368 ClassNotFoundException {
1369 Application app = (Application)clazz.newInstance();
1370 app.attach(context);
1371 return app;
1372 }
1373
1374 /**
1375 * Perform calling of the application's {@link Application#onCreate}
1376 * method. The default implementation simply calls through to that method.
1377 *
1378 * <p>Note: This method will be called immediately after {@link #onCreate(Bundle)}.
1379 * Often instrumentation tests start their test thread in onCreate(); you
1380 * need to be careful of races between these. (Well between it and
1381 * everything else, but let's start here.)
1382 *
1383 * @param app The application being created.
1384 */
1385 public void callApplicationOnCreate(Application app) {
1386 app.onCreate();
1387 }
1388
1389 /**
1390 * Perform instantiation of an {@link Activity} object. This method is intended for use with
1391 * unit tests, such as android.test.ActivityUnitTestCase. The activity will be useable
1392 * locally but will be missing some of the linkages necessary for use within the system.
1393 *
1394 * @param clazz The Class of the desired Activity
1395 * @param context The base context for the activity to use
1396 * @param token The token for this activity to communicate with
1397 * @param application The application object (if any)
1398 * @param intent The intent that started this Activity
1399 * @param info ActivityInfo from the manifest
1400 * @param title The title, typically retrieved from the ActivityInfo record
1401 * @param parent The parent Activity (if any)
1402 * @param id The embedded Id (if any)
1403 * @param lastNonConfigurationInstance Arbitrary object that will be
1404 * available via {@link Activity#getLastNonConfigurationInstance()
1405 * Activity.getLastNonConfigurationInstance()}.
1406 * @return Returns the instantiated activity
1407 * @throws InstantiationException
1408 * @throws IllegalAccessException
1409 */
1410 public Activity newActivity(Class<?> clazz, Context context,
1411 IBinder token, Application application, Intent intent, ActivityInfo info,
1412 CharSequence title, Activity parent, String id,
1413 Object lastNonConfigurationInstance) throws InstantiationException,
1414 IllegalAccessException {
1415 Activity activity = (Activity)clazz.newInstance();
1416 ActivityThread aThread = null;
1417 // Activity.attach expects a non-null Application Object.
1418 if (application == null) {
1419 application = new Application();
1420 }
1421 activity.attach(context, aThread, this, token, 0 /* ident */, application, intent,
1422 info, title, parent, id,
1423 (Activity.NonConfigurationInstances)lastNonConfigurationInstance,
1424 new Configuration(), null /* referrer */, null /* voiceInteractor */,
1425 null /* window */, null /* activityCallback */, null /* assistToken */,
1426 null /* shareableActivityToken */, null /* initialCallerInfoAccessToken */);
1427 return activity;
1428 }
1429
1430 /**
1431 * Perform instantiation of the process's {@link Activity} object. The
1432 * default implementation provides the normal system behavior.
1433 *
1434 * @param cl The ClassLoader with which to instantiate the object.
1435 * @param className The name of the class implementing the Activity
1436 * object.
1437 * @param intent The Intent object that specified the activity class being
1438 * instantiated.
1439 *
1440 * @return The newly instantiated Activity object.
1441 */
1442 public Activity newActivity(ClassLoader cl, String className,
1443 Intent intent)
1444 throws InstantiationException, IllegalAccessException,
1445 ClassNotFoundException {
1446 String pkg = intent != null && intent.getComponent() != null
1447 ? intent.getComponent().getPackageName() : null;
1448 return getFactory(pkg).instantiateActivity(cl, className, intent);
1449 }
1450
1451 private AppComponentFactory getFactory(String pkg) {
1452 if (pkg == null) {
1453 Log.e(TAG, "No pkg specified, disabling AppComponentFactory");
1454 return AppComponentFactory.DEFAULT;
1455 }
1456 if (mThread == null) {
1457 Log.e(TAG, "Uninitialized ActivityThread, likely app-created Instrumentation,"
1458 + " disabling AppComponentFactory", new Throwable());
1459 return AppComponentFactory.DEFAULT;
1460 }
1461 LoadedApk apk = mThread.peekPackageInfo(pkg, true);
1462 // This is in the case of starting up "android".
1463 if (apk == null) apk = mThread.getSystemContext().mPackageInfo;
1464 return apk.getAppFactory();
1465 }
1466
1467 /**
1468 * This should be called before {@link #checkStartActivityResult(int, Object)}, because
1469 * exceptions might be thrown while checking the results.
1470 */
1471 private void notifyStartActivityResult(int result, @Nullable Bundle options) {
1472 if (mActivityMonitors == null) {
1473 return;
1474 }
1475 synchronized (mSync) {
1476 final int size = mActivityMonitors.size();
1477 for (int i = 0; i < size; i++) {
1478 final ActivityMonitor am = mActivityMonitors.get(i);
1479 if (am.ignoreMatchingSpecificIntents()) {
1480 if (options == null) {
1481 options = ActivityOptions.makeBasic().toBundle();
1482 }
1483 am.onStartActivityResult(result, options);
1484 }
1485 }
1486 }
1487 }
1488
1489 private void prePerformCreate(Activity activity) {
1490 if (mWaitingActivities != null) {
1491 synchronized (mSync) {
1492 final int N = mWaitingActivities.size();
1493 for (int i=0; i<N; i++) {
1494 final ActivityWaiter aw = mWaitingActivities.get(i);
1495 final Intent intent = aw.intent;
1496 if (intent.filterEquals(activity.getIntent())) {
1497 aw.activity = activity;
1498 mMessageQueue.addIdleHandler(new ActivityGoing(aw));
1499 }
1500 }
1501 }
1502 }
1503 }
1504
1505 private void postPerformCreate(Activity activity) {
1506 if (mActivityMonitors != null) {
1507 synchronized (mSync) {
1508 final int N = mActivityMonitors.size();
1509 for (int i=0; i<N; i++) {
1510 final ActivityMonitor am = mActivityMonitors.get(i);
1511 am.match(activity, activity, activity.getIntent());
1512 }
1513 }
1514 }
1515 }
1516
1517 /**
1518 * Perform calling of an activity's {@link Activity#onCreate}
1519 * method. The default implementation simply calls through to that method.
1520 *
1521 * @param activity The activity being created.
1522 * @param icicle The previously frozen state (or null) to pass through to onCreate().
1523 */
1524 public void callActivityOnCreate(Activity activity, Bundle icicle) {
1525 prePerformCreate(activity);
1526 activity.performCreate(icicle);
1527 postPerformCreate(activity);
1528 }
1529
1530 /**
1531 * Perform calling of an activity's {@link Activity#onCreate}
1532 * method. The default implementation simply calls through to that method.
1533 * @param activity The activity being created.
1534 * @param icicle The previously frozen state (or null) to pass through to
1535 * @param persistentState The previously persisted state (or null)
1536 */
1537 public void callActivityOnCreate(Activity activity, Bundle icicle,
1538 PersistableBundle persistentState) {
1539 prePerformCreate(activity);
1540 activity.performCreate(icicle, persistentState);
1541 postPerformCreate(activity);
1542 }
1543
1544 public void callActivityOnDestroy(Activity activity) {
1545 // TODO: the following block causes intermittent hangs when using startActivity
1546 // temporarily comment out until root cause is fixed (bug 2630683)
1547// if (mWaitingActivities != null) {
1548// synchronized (mSync) {
1549// final int N = mWaitingActivities.size();
1550// for (int i=0; i<N; i++) {
1551// final ActivityWaiter aw = mWaitingActivities.get(i);
1552// final Intent intent = aw.intent;
1553// if (intent.filterEquals(activity.getIntent())) {
1554// aw.activity = activity;
1555// mMessageQueue.addIdleHandler(new ActivityGoing(aw));
1556// }
1557// }
1558// }
1559// }
1560
1561 activity.performDestroy();
1562 }
1563
1564 /**
1565 * Perform calling of an activity's {@link Activity#onRestoreInstanceState}
1566 * method. The default implementation simply calls through to that method.
1567 *
1568 * @param activity The activity being restored.
1569 * @param savedInstanceState The previously saved state being restored.
1570 */
1571 public void callActivityOnRestoreInstanceState(@NonNull Activity activity,
1572 @NonNull Bundle savedInstanceState) {
1573 activity.performRestoreInstanceState(savedInstanceState);
1574 }
1575
1576 /**
1577 * Perform calling of an activity's {@link Activity#onRestoreInstanceState}
1578 * method. The default implementation simply calls through to that method.
1579 *
1580 * @param activity The activity being restored.
1581 * @param savedInstanceState The previously saved state being restored (or null).
1582 * @param persistentState The previously persisted state (or null)
1583 */
1584 public void callActivityOnRestoreInstanceState(@NonNull Activity activity,
1585 @Nullable Bundle savedInstanceState,
1586 @Nullable PersistableBundle persistentState) {
1587 activity.performRestoreInstanceState(savedInstanceState, persistentState);
1588 }
1589
1590 /**
1591 * Perform calling of an activity's {@link Activity#onPostCreate} method.
1592 * The default implementation simply calls through to that method.
1593 *
1594 * @param activity The activity being created.
1595 * @param savedInstanceState The previously saved state (or null) to pass through to
1596 * onPostCreate().
1597 */
1598 public void callActivityOnPostCreate(@NonNull Activity activity,
1599 @Nullable Bundle savedInstanceState) {
1600 activity.onPostCreate(savedInstanceState);
1601 }
1602
1603 /**
1604 * Perform calling of an activity's {@link Activity#onPostCreate} method.
1605 * The default implementation simply calls through to that method.
1606 *
1607 * @param activity The activity being created.
1608 * @param savedInstanceState The previously frozen state (or null) to pass through to
1609 * onPostCreate().
1610 * @param persistentState The previously persisted state (or null)
1611 */
1612 public void callActivityOnPostCreate(@NonNull Activity activity,
1613 @Nullable Bundle savedInstanceState,
1614 @Nullable PersistableBundle persistentState) {
1615 activity.onPostCreate(savedInstanceState, persistentState);
1616 }
1617
1618 /**
1619 * Perform calling of an activity's {@link Activity#onNewIntent}
1620 * method. The default implementation simply calls through to that method.
1621 *
1622 * @param activity The activity receiving a new Intent.
1623 * @param intent The new intent being received.
1624 */
1625 public void callActivityOnNewIntent(Activity activity, Intent intent) {
1626 if (android.security.Flags.contentUriPermissionApis()) {
1627 activity.performNewIntent(intent, new ComponentCaller(activity.getActivityToken(),
1628 /* callerToken */ null));
1629 } else {
1630 activity.performNewIntent(intent);
1631 }
1632 }
1633
1634 /**
1635 * Same as {@link #callActivityOnNewIntent(Activity, Intent)}, but with an extra parameter for
1636 * the {@link ComponentCaller} instance associated with the app that sent the intent.
1637 *
1638 * @param activity The activity receiving a new Intent.
1639 * @param intent The new intent being received.
1640 * @param caller The {@link ComponentCaller} instance that launched the activity with the new
1641 * intent.
1642 */
1643 @FlaggedApi(android.security.Flags.FLAG_CONTENT_URI_PERMISSION_APIS)
1644 public void callActivityOnNewIntent(@NonNull Activity activity, @NonNull Intent intent,
1645 @NonNull ComponentCaller caller) {
1646 activity.performNewIntent(intent, caller);
1647 }
1648
1649 /**
1650 * @hide
1651 */
1652 @FlaggedApi(android.security.Flags.FLAG_CONTENT_URI_PERMISSION_APIS)
1653 public void callActivityOnNewIntent(Activity activity, ReferrerIntent intent,
1654 @NonNull ComponentCaller caller) {
1655 internalCallActivityOnNewIntent(activity, intent, caller);
1656 }
1657
1658 @FlaggedApi(android.security.Flags.FLAG_CONTENT_URI_PERMISSION_APIS)
1659 private void internalCallActivityOnNewIntent(Activity activity, ReferrerIntent intent,
1660 @NonNull ComponentCaller caller) {
1661 final String oldReferrer = activity.mReferrer;
1662 try {
1663 if (intent != null) {
1664 activity.mReferrer = intent.mReferrer;
1665 }
1666 Intent newIntent = intent != null ? new Intent(intent) : null;
1667 callActivityOnNewIntent(activity, newIntent, caller);
1668 } finally {
1669 activity.mReferrer = oldReferrer;
1670 }
1671 }
1672
1673 /**
1674 * @hide
1675 */
1676 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
1677 public void callActivityOnNewIntent(Activity activity, ReferrerIntent intent) {
1678 if (android.security.Flags.contentUriPermissionApis()) {
1679 internalCallActivityOnNewIntent(activity, intent, new ComponentCaller(
1680 activity.getActivityToken(), /* callerToken */ null));
1681 } else {
1682 final String oldReferrer = activity.mReferrer;
1683 try {
1684 if (intent != null) {
1685 activity.mReferrer = intent.mReferrer;
1686 }
1687 callActivityOnNewIntent(activity, intent != null ? new Intent(intent) : null);
1688 } finally {
1689 activity.mReferrer = oldReferrer;
1690 }
1691 }
1692 }
1693
1694 /**
1695 * Perform calling of an activity's {@link Activity#onStart}
1696 * method. The default implementation simply calls through to that method.
1697 *
1698 * @param activity The activity being started.
1699 */
1700 public void callActivityOnStart(Activity activity) {
1701 activity.onStart();
1702 }
1703
1704 /**
1705 * Perform calling of an activity's {@link Activity#onRestart}
1706 * method. The default implementation simply calls through to that method.
1707 *
1708 * @param activity The activity being restarted.
1709 */
1710 public void callActivityOnRestart(Activity activity) {
1711 activity.onRestart();
1712 }
1713
1714 /**
1715 * Perform calling of an activity's {@link Activity#onResume} method. The
1716 * default implementation simply calls through to that method.
1717 *
1718 * @param activity The activity being resumed.
1719 */
1720 public void callActivityOnResume(Activity activity) {
1721 activity.mResumed = true;
1722 activity.onResume();
1723
1724 if (mActivityMonitors != null) {
1725 synchronized (mSync) {
1726 final int N = mActivityMonitors.size();
1727 for (int i=0; i<N; i++) {
1728 final ActivityMonitor am = mActivityMonitors.get(i);
1729 am.match(activity, activity, activity.getIntent());
1730 }
1731 }
1732 }
1733 }
1734
1735 /**
1736 * Perform calling of an activity's {@link Activity#onStop}
1737 * method. The default implementation simply calls through to that method.
1738 *
1739 * @param activity The activity being stopped.
1740 */
1741 public void callActivityOnStop(Activity activity) {
1742 activity.onStop();
1743 }
1744
1745 /**
1746 * Perform calling of an activity's {@link Activity#onSaveInstanceState}
1747 * method. The default implementation simply calls through to that method.
1748 *
1749 * @param activity The activity being saved.
1750 * @param outState The bundle to pass to the call.
1751 */
1752 public void callActivityOnSaveInstanceState(@NonNull Activity activity,
1753 @NonNull Bundle outState) {
1754 activity.performSaveInstanceState(outState);
1755 }
1756
1757 /**
1758 * Perform calling of an activity's {@link Activity#onSaveInstanceState}
1759 * method. The default implementation simply calls through to that method.
1760 * @param activity The activity being saved.
1761 * @param outState The bundle to pass to the call.
1762 * @param outPersistentState The persistent bundle to pass to the call.
1763 */
1764 public void callActivityOnSaveInstanceState(@NonNull Activity activity,
1765 @NonNull Bundle outState, @NonNull PersistableBundle outPersistentState) {
1766 activity.performSaveInstanceState(outState, outPersistentState);
1767 }
1768
1769 /**
1770 * Perform calling of an activity's {@link Activity#onPause} method. The
1771 * default implementation simply calls through to that method.
1772 *
1773 * @param activity The activity being paused.
1774 */
1775 public void callActivityOnPause(Activity activity) {
1776 activity.performPause();
1777 }
1778
1779 /**
1780 * Perform calling of an activity's {@link Activity#onUserLeaveHint} method.
1781 * The default implementation simply calls through to that method.
1782 *
1783 * @param activity The activity being notified that the user has navigated away
1784 */
1785 public void callActivityOnUserLeaving(Activity activity) {
1786 activity.performUserLeaving();
1787 }
1788
1789 /**
1790 * Perform calling of an activity's {@link Activity#onPictureInPictureRequested} method.
1791 * The default implementation simply calls through to that method.
1792 *
1793 * @param activity The activity being notified that picture-in-picture is being requested.
1794 */
1795 public void callActivityOnPictureInPictureRequested(@NonNull Activity activity) {
1796 activity.onPictureInPictureRequested();
1797 }
1798
1799 /*
1800 * Starts allocation counting. This triggers a gc and resets the counts.
1801 *
1802 * @deprecated Accurate counting is a burden on the runtime and may be removed.
1803 */
1804 @Deprecated
1805 public void startAllocCounting() {
1806 // Before we start trigger a GC and reset the debug counts. Run the
1807 // finalizers and another GC before starting and stopping the alloc
1808 // counts. This will free up any objects that were just sitting around
1809 // waiting for their finalizers to be run.
1810 Runtime.getRuntime().gc();
1811 Runtime.getRuntime().runFinalization();
1812 Runtime.getRuntime().gc();
1813
1814 Debug.resetAllCounts();
1815
1816 // start the counts
1817 Debug.startAllocCounting();
1818 }
1819
1820 /*
1821 * Stops allocation counting.
1822 *
1823 * @deprecated Accurate counting is a burden on the runtime and may be removed.
1824 */
1825 @Deprecated
1826 public void stopAllocCounting() {
1827 Runtime.getRuntime().gc();
1828 Runtime.getRuntime().runFinalization();
1829 Runtime.getRuntime().gc();
1830 Debug.stopAllocCounting();
1831 }
1832
1833 /**
1834 * If Results already contains Key, it appends Value to the key's ArrayList
1835 * associated with the key. If the key doesn't already exist in results, it
1836 * adds the key/value pair to results.
1837 */
1838 private void addValue(String key, int value, Bundle results) {
1839 if (results.containsKey(key)) {
1840 List<Integer> list = results.getIntegerArrayList(key);
1841 if (list != null) {
1842 list.add(value);
1843 }
1844 } else {
1845 ArrayList<Integer> list = new ArrayList<Integer>();
1846 list.add(value);
1847 results.putIntegerArrayList(key, list);
1848 }
1849 }
1850
1851 /**
1852 * Returns a bundle with the current results from the allocation counting.
1853 */
1854 public Bundle getAllocCounts() {
1855 Bundle results = new Bundle();
1856 results.putLong("global_alloc_count", Debug.getGlobalAllocCount());
1857 results.putLong("global_alloc_size", Debug.getGlobalAllocSize());
1858 results.putLong("global_freed_count", Debug.getGlobalFreedCount());
1859 results.putLong("global_freed_size", Debug.getGlobalFreedSize());
1860 results.putLong("gc_invocation_count", Debug.getGlobalGcInvocationCount());
1861 return results;
1862 }
1863
1864 /**
1865 * Returns a bundle with the counts for various binder counts for this process. Currently the only two that are
1866 * reported are the number of send and the number of received transactions.
1867 */
1868 public Bundle getBinderCounts() {
1869 Bundle results = new Bundle();
1870 results.putLong("sent_transactions", Debug.getBinderSentTransactions());
1871 results.putLong("received_transactions", Debug.getBinderReceivedTransactions());
1872 return results;
1873 }
1874
1875 /**
1876 * Description of a Activity execution result to return to the original
1877 * activity.
1878 */
1879 public static final class ActivityResult {
1880 /**
1881 * Create a new activity result. See {@link Activity#setResult} for
1882 * more information.
1883 *
1884 * @param resultCode The result code to propagate back to the
1885 * originating activity, often RESULT_CANCELED or RESULT_OK
1886 * @param resultData The data to propagate back to the originating
1887 * activity.
1888 */
1889 public ActivityResult(int resultCode, Intent resultData) {
1890 mResultCode = resultCode;
1891 mResultData = resultData;
1892 }
1893
1894 /**
1895 * Retrieve the result code contained in this result.
1896 */
1897 public int getResultCode() {
1898 return mResultCode;
1899 }
1900
1901 /**
1902 * Retrieve the data contained in this result.
1903 */
1904 public Intent getResultData() {
1905 return mResultData;
1906 }
1907
1908 private final int mResultCode;
1909 private final Intent mResultData;
1910 }
1911
1912 /**
1913 * Execute a startActivity call made by the application. The default
1914 * implementation takes care of updating any active {@link ActivityMonitor}
1915 * objects and dispatches this call to the system activity manager; you can
1916 * override this to watch for the application to start an activity, and
1917 * modify what happens when it does.
1918 *
1919 * <p>This method returns an {@link ActivityResult} object, which you can
1920 * use when intercepting application calls to avoid performing the start
1921 * activity action but still return the result the application is
1922 * expecting. To do this, override this method to catch the call to start
1923 * activity so that it returns a new ActivityResult containing the results
1924 * you would like the application to see, and don't call up to the super
1925 * class. Note that an application is only expecting a result if
1926 * <var>requestCode</var> is &gt;= 0.
1927 *
1928 * <p>This method throws {@link android.content.ActivityNotFoundException}
1929 * if there was no Activity found to run the given Intent.
1930 *
1931 * @param who The Context from which the activity is being started.
1932 * @param contextThread The main thread of the Context from which the activity
1933 * is being started.
1934 * @param token Internal token identifying to the system who is starting
1935 * the activity; may be null.
1936 * @param target Which activity is performing the start (and thus receiving
1937 * any result); may be null if this call is not being made
1938 * from an activity.
1939 * @param intent The actual Intent to start.
1940 * @param requestCode Identifier for this request's result; less than zero
1941 * if the caller is not expecting a result.
1942 * @param options Addition options.
1943 *
1944 * @return To force the return of a particular result, return an
1945 * ActivityResult object containing the desired data; otherwise
1946 * return null. The default implementation always returns null.
1947 *
1948 * @throws android.content.ActivityNotFoundException
1949 *
1950 * @see Activity#startActivity(Intent)
1951 * @see Activity#startActivityForResult(Intent, int)
1952 *
1953 * {@hide}
1954 */
1955 @UnsupportedAppUsage
1956 public ActivityResult execStartActivity(
1957 Context who, IBinder contextThread, IBinder token, Activity target,
1958 Intent intent, int requestCode, Bundle options) {
1959 if (DEBUG_START_ACTIVITY) {
1960 Log.d(TAG, "startActivity: who=" + who + " source=" + target + " intent=" + intent
1961 + " requestCode=" + requestCode + " options=" + options, new Throwable());
1962 }
1963 Objects.requireNonNull(intent);
1964 IApplicationThread whoThread = (IApplicationThread) contextThread;
1965 Uri referrer = target != null ? target.onProvideReferrer() : null;
1966 if (referrer != null) {
1967 intent.putExtra(Intent.EXTRA_REFERRER, referrer);
1968 }
1969 if (isSdkSandboxAllowedToStartActivities()) {
1970 adjustIntentForCtsInSdkSandboxInstrumentation(intent);
1971 }
1972 if (mActivityMonitors != null) {
1973 synchronized (mSync) {
1974 final int N = mActivityMonitors.size();
1975 for (int i=0; i<N; i++) {
1976 final ActivityMonitor am = mActivityMonitors.get(i);
1977 ActivityResult result = null;
1978 if (am.ignoreMatchingSpecificIntents()) {
1979 if (options == null) {
1980 options = ActivityOptions.makeBasic().toBundle();
1981 }
1982 result = am.onStartActivity(who, intent, options);
1983 }
1984 if (result != null) {
1985 am.mHits++;
1986 return result;
1987 } else if (am.match(who, null, intent)) {
1988 am.mHits++;
1989 if (am.isBlocking()) {
1990 return requestCode >= 0 ? am.getResult() : null;
1991 }
1992 break;
1993 }
1994 }
1995 }
1996 }
1997 try {
1998 intent.migrateExtraStreamToClipData(who);
1999 intent.prepareToLeaveProcess(who);
2000 int result = ActivityTaskManager.getService().startActivity(whoThread,
2001 who.getOpPackageName(), who.getAttributionTag(), intent,
2002 intent.resolveTypeIfNeeded(who.getContentResolver()), token,
2003 target != null ? target.mEmbeddedID : null, requestCode, 0, null, options);
2004 notifyStartActivityResult(result, options);
2005 checkStartActivityResult(result, intent);
2006 } catch (RemoteException e) {
2007 throw new RuntimeException("Failure from system", e);
2008 }
2009 return null;
2010 }
2011
2012 /**
2013 * Like {@link #execStartActivity(Context, IBinder, IBinder, Activity, Intent, int, Bundle)},
2014 * but accepts an array of activities to be started. Note that active
2015 * {@link ActivityMonitor} objects only match against the first activity in
2016 * the array.
2017 *
2018 * {@hide}
2019 */
2020 @UnsupportedAppUsage
2021 public void execStartActivities(Context who, IBinder contextThread,
2022 IBinder token, Activity target, Intent[] intents, Bundle options) {
2023 execStartActivitiesAsUser(who, contextThread, token, target, intents, options,
2024 who.getUserId());
2025 }
2026
2027 /**
2028 * Like {@link #execStartActivity(Context, IBinder, IBinder, Activity, Intent, int, Bundle)},
2029 * but accepts an array of activities to be started. Note that active
2030 * {@link ActivityMonitor} objects only match against the first activity in
2031 * the array.
2032 *
2033 * @return The corresponding flag {@link ActivityManager#START_CANCELED},
2034 * {@link ActivityManager#START_SUCCESS} etc. indicating whether the launch was
2035 * successful.
2036 *
2037 * {@hide}
2038 */
2039 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
2040 public int execStartActivitiesAsUser(Context who, IBinder contextThread,
2041 IBinder token, Activity target, Intent[] intents, Bundle options,
2042 int userId) {
2043 if (DEBUG_START_ACTIVITY) {
2044 StringJoiner joiner = new StringJoiner(", ");
2045 for (Intent i : intents) {
2046 joiner.add(i.toString());
2047 }
2048 Log.d(TAG, "startActivities: who=" + who + " source=" + target + " userId=" + userId
2049 + " intents=[" + joiner + "] options=" + options, new Throwable());
2050 }
2051 Objects.requireNonNull(intents);
2052 for (int i = intents.length - 1; i >= 0; i--) {
2053 Objects.requireNonNull(intents[i]);
2054 }
2055 IApplicationThread whoThread = (IApplicationThread) contextThread;
2056 if (isSdkSandboxAllowedToStartActivities()) {
2057 for (Intent intent : intents) {
2058 adjustIntentForCtsInSdkSandboxInstrumentation(intent);
2059 }
2060 }
2061 if (mActivityMonitors != null) {
2062 synchronized (mSync) {
2063 final int N = mActivityMonitors.size();
2064 for (int i=0; i<N; i++) {
2065 final ActivityMonitor am = mActivityMonitors.get(i);
2066 ActivityResult result = null;
2067 if (am.ignoreMatchingSpecificIntents()) {
2068 if (options == null) {
2069 options = ActivityOptions.makeBasic().toBundle();
2070 }
2071 result = am.onStartActivity(who, intents[0], options);
2072 }
2073 if (result != null) {
2074 am.mHits++;
2075 return ActivityManager.START_CANCELED;
2076 } else if (am.match(who, null, intents[0])) {
2077 am.mHits++;
2078 if (am.isBlocking()) {
2079 return ActivityManager.START_CANCELED;
2080 }
2081 break;
2082 }
2083 }
2084 }
2085 }
2086 try {
2087 String[] resolvedTypes = new String[intents.length];
2088 for (int i=0; i<intents.length; i++) {
2089 intents[i].migrateExtraStreamToClipData(who);
2090 intents[i].prepareToLeaveProcess(who);
2091 resolvedTypes[i] = intents[i].resolveTypeIfNeeded(who.getContentResolver());
2092 }
2093 int result = ActivityTaskManager.getService().startActivities(whoThread,
2094 who.getOpPackageName(), who.getAttributionTag(), intents, resolvedTypes,
2095 token, options, userId);
2096 notifyStartActivityResult(result, options);
2097 checkStartActivityResult(result, intents[0]);
2098 return result;
2099 } catch (RemoteException e) {
2100 throw new RuntimeException("Failure from system", e);
2101 }
2102 }
2103
2104 /**
2105 * Like {@link #execStartActivity(android.content.Context, android.os.IBinder,
2106 * android.os.IBinder, String, android.content.Intent, int, android.os.Bundle)},
2107 * but for calls from a {@link Fragment}.
2108 *
2109 * @param who The Context from which the activity is being started.
2110 * @param contextThread The main thread of the Context from which the activity
2111 * is being started.
2112 * @param token Internal token identifying to the system who is starting
2113 * the activity; may be null.
2114 * @param target Which element is performing the start (and thus receiving
2115 * any result).
2116 * @param intent The actual Intent to start.
2117 * @param requestCode Identifier for this request's result; less than zero
2118 * if the caller is not expecting a result.
2119 *
2120 * @return To force the return of a particular result, return an
2121 * ActivityResult object containing the desired data; otherwise
2122 * return null. The default implementation always returns null.
2123 *
2124 * @throws android.content.ActivityNotFoundException
2125 *
2126 * @see Activity#startActivity(Intent)
2127 * @see Activity#startActivityForResult(Intent, int)
2128 *
2129 * {@hide}
2130 */
2131 @UnsupportedAppUsage
2132 public ActivityResult execStartActivity(
2133 Context who, IBinder contextThread, IBinder token, String target,
2134 Intent intent, int requestCode, Bundle options) {
2135 if (DEBUG_START_ACTIVITY) {
2136 Log.d(TAG, "startActivity: who=" + who + " target=" + target
2137 + " intent=" + intent + " requestCode=" + requestCode
2138 + " options=" + options, new Throwable());
2139 }
2140 Objects.requireNonNull(intent);
2141 IApplicationThread whoThread = (IApplicationThread) contextThread;
2142 if (isSdkSandboxAllowedToStartActivities()) {
2143 adjustIntentForCtsInSdkSandboxInstrumentation(intent);
2144 }
2145 if (mActivityMonitors != null) {
2146 synchronized (mSync) {
2147 final int N = mActivityMonitors.size();
2148 for (int i=0; i<N; i++) {
2149 final ActivityMonitor am = mActivityMonitors.get(i);
2150 ActivityResult result = null;
2151 if (am.ignoreMatchingSpecificIntents()) {
2152 if (options == null) {
2153 options = ActivityOptions.makeBasic().toBundle();
2154 }
2155 result = am.onStartActivity(who, intent, options);
2156 }
2157 if (result != null) {
2158 am.mHits++;
2159 return result;
2160 } else if (am.match(who, null, intent)) {
2161 am.mHits++;
2162 if (am.isBlocking()) {
2163 return requestCode >= 0 ? am.getResult() : null;
2164 }
2165 break;
2166 }
2167 }
2168 }
2169 }
2170 try {
2171 intent.migrateExtraStreamToClipData(who);
2172 intent.prepareToLeaveProcess(who);
2173 int result = ActivityTaskManager.getService().startActivity(whoThread,
2174 who.getOpPackageName(), who.getAttributionTag(), intent,
2175 intent.resolveTypeIfNeeded(who.getContentResolver()), token, target,
2176 requestCode, 0, null, options);
2177 notifyStartActivityResult(result, options);
2178 checkStartActivityResult(result, intent);
2179 } catch (RemoteException e) {
2180 throw new RuntimeException("Failure from system", e);
2181 }
2182 return null;
2183 }
2184
2185 /**
2186 * Like {@link #execStartActivity(Context, IBinder, IBinder, Activity, Intent, int, Bundle)},
2187 * but for starting as a particular user.
2188 *
2189 * @param who The Context from which the activity is being started.
2190 * @param contextThread The main thread of the Context from which the activity
2191 * is being started.
2192 * @param token Internal token identifying to the system who is starting
2193 * the activity; may be null.
2194 * @param target Which fragment is performing the start (and thus receiving
2195 * any result).
2196 * @param intent The actual Intent to start.
2197 * @param requestCode Identifier for this request's result; less than zero
2198 * if the caller is not expecting a result.
2199 *
2200 * @return To force the return of a particular result, return an
2201 * ActivityResult object containing the desired data; otherwise
2202 * return null. The default implementation always returns null.
2203 *
2204 * @throws android.content.ActivityNotFoundException
2205 *
2206 * @see Activity#startActivity(Intent)
2207 * @see Activity#startActivityForResult(Intent, int)
2208 *
2209 * {@hide}
2210 */
2211 @UnsupportedAppUsage
2212 public ActivityResult execStartActivity(
2213 Context who, IBinder contextThread, IBinder token, String resultWho,
2214 Intent intent, int requestCode, Bundle options, UserHandle user) {
2215 if (DEBUG_START_ACTIVITY) {
2216 Log.d(TAG, "startActivity: who=" + who + " user=" + user + " intent=" + intent
2217 + " requestCode=" + requestCode + " resultWho=" + resultWho
2218 + " options=" + options, new Throwable());
2219 }
2220 Objects.requireNonNull(intent);
2221 IApplicationThread whoThread = (IApplicationThread) contextThread;
2222 if (isSdkSandboxAllowedToStartActivities()) {
2223 adjustIntentForCtsInSdkSandboxInstrumentation(intent);
2224 }
2225 if (mActivityMonitors != null) {
2226 synchronized (mSync) {
2227 final int N = mActivityMonitors.size();
2228 for (int i=0; i<N; i++) {
2229 final ActivityMonitor am = mActivityMonitors.get(i);
2230 ActivityResult result = null;
2231 if (am.ignoreMatchingSpecificIntents()) {
2232 if (options == null) {
2233 options = ActivityOptions.makeBasic().toBundle();
2234 }
2235 result = am.onStartActivity(who, intent, options);
2236 }
2237 if (result != null) {
2238 am.mHits++;
2239 return result;
2240 } else if (am.match(who, null, intent)) {
2241 am.mHits++;
2242 if (am.isBlocking()) {
2243 return requestCode >= 0 ? am.getResult() : null;
2244 }
2245 break;
2246 }
2247 }
2248 }
2249 }
2250 try {
2251 intent.migrateExtraStreamToClipData(who);
2252 intent.prepareToLeaveProcess(who);
2253 int result = ActivityTaskManager.getService().startActivityAsUser(whoThread,
2254 who.getOpPackageName(), who.getAttributionTag(), intent,
2255 intent.resolveTypeIfNeeded(who.getContentResolver()), token, resultWho,
2256 requestCode, 0, null, options, user.getIdentifier());
2257 notifyStartActivityResult(result, options);
2258 checkStartActivityResult(result, intent);
2259 } catch (RemoteException e) {
2260 throw new RuntimeException("Failure from system", e);
2261 }
2262 return null;
2263 }
2264
2265 /**
2266 * Special version!
2267 * @hide
2268 */
2269 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
2270 public ActivityResult execStartActivityAsCaller(
2271 Context who, IBinder contextThread, IBinder token, Activity target,
2272 Intent intent, int requestCode, Bundle options,
2273 boolean ignoreTargetSecurity, int userId) {
2274 if (DEBUG_START_ACTIVITY) {
2275 Log.d(TAG, "startActivity: who=" + who + " source=" + target + " userId=" + userId
2276 + " intent=" + intent + " requestCode=" + requestCode
2277 + " ignoreTargetSecurity=" + ignoreTargetSecurity + " options=" + options,
2278 new Throwable());
2279 }
2280 Objects.requireNonNull(intent);
2281 IApplicationThread whoThread = (IApplicationThread) contextThread;
2282 if (isSdkSandboxAllowedToStartActivities()) {
2283 adjustIntentForCtsInSdkSandboxInstrumentation(intent);
2284 }
2285 if (mActivityMonitors != null) {
2286 synchronized (mSync) {
2287 final int N = mActivityMonitors.size();
2288 for (int i=0; i<N; i++) {
2289 final ActivityMonitor am = mActivityMonitors.get(i);
2290 ActivityResult result = null;
2291 if (am.ignoreMatchingSpecificIntents()) {
2292 if (options == null) {
2293 options = ActivityOptions.makeBasic().toBundle();
2294 }
2295 result = am.onStartActivity(who, intent, options);
2296 }
2297 if (result != null) {
2298 am.mHits++;
2299 return result;
2300 } else if (am.match(who, null, intent)) {
2301 am.mHits++;
2302 if (am.isBlocking()) {
2303 return requestCode >= 0 ? am.getResult() : null;
2304 }
2305 break;
2306 }
2307 }
2308 }
2309 }
2310 try {
2311 intent.migrateExtraStreamToClipData(who);
2312 intent.prepareToLeaveProcess(who);
2313 int result = ActivityTaskManager.getService()
2314 .startActivityAsCaller(whoThread, who.getOpPackageName(), intent,
2315 intent.resolveTypeIfNeeded(who.getContentResolver()),
2316 token, target != null ? target.mEmbeddedID : null,
2317 requestCode, 0, null, options,
2318 ignoreTargetSecurity, userId);
2319 notifyStartActivityResult(result, options);
2320 checkStartActivityResult(result, intent);
2321 } catch (RemoteException e) {
2322 throw new RuntimeException("Failure from system", e);
2323 }
2324 return null;
2325 }
2326
2327 /**
2328 * Special version!
2329 * @hide
2330 */
2331 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
2332 public void execStartActivityFromAppTask(
2333 Context who, IBinder contextThread, IAppTask appTask,
2334 Intent intent, Bundle options) {
2335 if (DEBUG_START_ACTIVITY) {
2336 Log.d(TAG, "startActivity: who=" + who + " intent=" + intent
2337 + " options=" + options, new Throwable());
2338 }
2339 Objects.requireNonNull(intent);
2340 IApplicationThread whoThread = (IApplicationThread) contextThread;
2341 if (isSdkSandboxAllowedToStartActivities()) {
2342 adjustIntentForCtsInSdkSandboxInstrumentation(intent);
2343 }
2344 if (mActivityMonitors != null) {
2345 synchronized (mSync) {
2346 final int N = mActivityMonitors.size();
2347 for (int i=0; i<N; i++) {
2348 final ActivityMonitor am = mActivityMonitors.get(i);
2349 ActivityResult result = null;
2350 if (am.ignoreMatchingSpecificIntents()) {
2351 if (options == null) {
2352 options = ActivityOptions.makeBasic().toBundle();
2353 }
2354 result = am.onStartActivity(who, intent, options);
2355 }
2356 if (result != null) {
2357 am.mHits++;
2358 return;
2359 } else if (am.match(who, null, intent)) {
2360 am.mHits++;
2361 if (am.isBlocking()) {
2362 return;
2363 }
2364 break;
2365 }
2366 }
2367 }
2368 }
2369 try {
2370 intent.migrateExtraStreamToClipData(who);
2371 intent.prepareToLeaveProcess(who);
2372 int result = appTask.startActivity(whoThread.asBinder(), who.getOpPackageName(),
2373 who.getAttributionTag(), intent,
2374 intent.resolveTypeIfNeeded(who.getContentResolver()), options);
2375 notifyStartActivityResult(result, options);
2376 checkStartActivityResult(result, intent);
2377 } catch (RemoteException e) {
2378 throw new RuntimeException("Failure from system", e);
2379 }
2380 return;
2381 }
2382
2383 /*package*/ final void init(ActivityThread thread,
2384 Context instrContext, Context appContext, ComponentName component,
2385 IInstrumentationWatcher watcher, IUiAutomationConnection uiAutomationConnection) {
2386 mThread = thread;
2387 mMessageQueue = mThread.getLooper().myQueue();
2388 mInstrContext = instrContext;
2389 mAppContext = appContext;
2390 mComponent = component;
2391 mWatcher = watcher;
2392 mUiAutomationConnection = uiAutomationConnection;
2393 }
2394
2395 /**
2396 * Only sets the ActivityThread up, keeps everything else null because app is not being
2397 * instrumented.
2398 */
2399 final void basicInit(ActivityThread thread) {
2400 mThread = thread;
2401 }
2402
2403 /**
2404 * Only sets the Context up, keeps everything else null.
2405 *
2406 * @hide
2407 */
2408 @android.ravenwood.annotation.RavenwoodKeep
2409 public final void basicInit(Context context) {
2410 mInstrContext = context;
2411 mAppContext = context;
2412 }
2413
2414 /** @hide */
2415 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
2416 public static void checkStartActivityResult(int res, Object intent) {
2417 if (!ActivityManager.isStartResultFatalError(res)) {
2418 return;
2419 }
2420
2421 switch (res) {
2422 case ActivityManager.START_INTENT_NOT_RESOLVED:
2423 case ActivityManager.START_CLASS_NOT_FOUND:
2424 if (intent instanceof Intent && ((Intent)intent).getComponent() != null)
2425 throw new ActivityNotFoundException(
2426 "Unable to find explicit activity class "
2427 + ((Intent)intent).getComponent().toShortString()
2428 + "; have you declared this activity in your AndroidManifest.xml"
2429 + ", or does your intent not match its declared <intent-filter>?");
2430 throw new ActivityNotFoundException(
2431 "No Activity found to handle " + intent);
2432 case ActivityManager.START_PERMISSION_DENIED:
2433 throw new SecurityException("Not allowed to start activity "
2434 + intent);
2435 case ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT:
2436 throw new AndroidRuntimeException(
2437 "FORWARD_RESULT_FLAG used while also requesting a result");
2438 case ActivityManager.START_NOT_ACTIVITY:
2439 throw new IllegalArgumentException(
2440 "PendingIntent is not an activity");
2441 case ActivityManager.START_NOT_VOICE_COMPATIBLE:
2442 throw new SecurityException(
2443 "Starting under voice control not allowed for: " + intent);
2444 case ActivityManager.START_VOICE_NOT_ACTIVE_SESSION:
2445 throw new IllegalStateException(
2446 "Session calling startVoiceActivity does not match active session");
2447 case ActivityManager.START_VOICE_HIDDEN_SESSION:
2448 throw new IllegalStateException(
2449 "Cannot start voice activity on a hidden session");
2450 case ActivityManager.START_ASSISTANT_NOT_ACTIVE_SESSION:
2451 throw new IllegalStateException(
2452 "Session calling startAssistantActivity does not match active session");
2453 case ActivityManager.START_ASSISTANT_HIDDEN_SESSION:
2454 throw new IllegalStateException(
2455 "Cannot start assistant activity on a hidden session");
2456 case ActivityManager.START_CANCELED:
2457 throw new AndroidRuntimeException("Activity could not be started for "
2458 + intent);
2459 default:
2460 throw new AndroidRuntimeException("Unknown error code "
2461 + res + " when starting " + intent);
2462 }
2463 }
2464
2465 private final void validateNotAppThread() {
2466 if (Looper.myLooper() == Looper.getMainLooper()) {
2467 throw new RuntimeException(
2468 "This method can not be called from the main application thread");
2469 }
2470 }
2471
2472 /**
2473 * Gets the {@link UiAutomation} instance with no flags set.
2474 * <p>
2475 * <strong>Note:</strong> The APIs exposed via the returned {@link UiAutomation}
2476 * work across application boundaries while the APIs exposed by the instrumentation
2477 * do not. For example, {@link Instrumentation#sendPointerSync(MotionEvent)} will
2478 * not allow you to inject the event in an app different from the instrumentation
2479 * target, while {@link UiAutomation#injectInputEvent(android.view.InputEvent, boolean)}
2480 * will work regardless of the current application.
2481 * </p>
2482 * <p>
2483 * A typical test case should be using either the {@link UiAutomation} or
2484 * {@link Instrumentation} APIs. Using both APIs at the same time is not
2485 * a mistake by itself but a client has to be aware of the APIs limitations.
2486 * </p>
2487 * <p>
2488 * Equivalent to {@code getUiAutomation(0)}. If a {@link UiAutomation} exists with different
2489 * flags, the flags on that instance will be changed, and then it will be returned.
2490 * </p>
2491 * <p>
2492 * Compatibility mode: This method is infallible for apps targeted for
2493 * {@link Build.VERSION_CODES#R} and earlier versions; for apps targeted for later versions, it
2494 * will return null if {@link UiAutomation} fails to connect. The caller can check the return
2495 * value and retry on error.
2496 * </p>
2497 *
2498 * @return The UI automation instance.
2499 *
2500 * @see UiAutomation
2501 */
2502 public UiAutomation getUiAutomation() {
2503 return getUiAutomation(0);
2504 }
2505
2506 /**
2507 * Gets the {@link UiAutomation} instance with flags set.
2508 * <p>
2509 * <strong>Note:</strong> The APIs exposed via the returned {@link UiAutomation}
2510 * work across application boundaries while the APIs exposed by the instrumentation
2511 * do not. For example, {@link Instrumentation#sendPointerSync(MotionEvent)} will
2512 * not allow you to inject the event in an app different from the instrumentation
2513 * target, while {@link UiAutomation#injectInputEvent(android.view.InputEvent, boolean)}
2514 * will work regardless of the current application.
2515 * </p>
2516 * <p>
2517 * A typical test case should be using either the {@link UiAutomation} or
2518 * {@link Instrumentation} APIs. Using both APIs at the same time is not
2519 * a mistake by itself but a client has to be aware of the APIs limitations.
2520 * </p>
2521 * <p>
2522 * If a {@link UiAutomation} exists with different flags, the flags on that instance will be
2523 * changed, and then it will be returned.
2524 * </p>
2525 * <p>
2526 * Compatibility mode: This method is infallible for apps targeted for
2527 * {@link Build.VERSION_CODES#R} and earlier versions; for apps targeted for later versions, it
2528 * will return null if {@link UiAutomation} fails to connect. The caller can check the return
2529 * value and retry on error.
2530 * </p>
2531 *
2532 * @param flags The flags to be passed to the UiAutomation, for example
2533 * {@link UiAutomation#FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES},
2534 * {@link UiAutomation#FLAG_DONT_USE_ACCESSIBILITY}.
2535 *
2536 * @return The UI automation instance.
2537 *
2538 * @see UiAutomation
2539 */
2540 public UiAutomation getUiAutomation(@UiAutomationFlags int flags) {
2541 boolean mustCreateNewAutomation = (mUiAutomation == null) || (mUiAutomation.isDestroyed());
2542
2543 if (mUiAutomationConnection != null) {
2544 if (!mustCreateNewAutomation && (mUiAutomation.getFlags() == flags)) {
2545 return mUiAutomation;
2546 }
2547 if (mustCreateNewAutomation) {
2548 mUiAutomation = new UiAutomation(getTargetContext(), mUiAutomationConnection);
2549 } else {
2550 mUiAutomation.disconnect();
2551 }
2552 if (getTargetContext().getApplicationInfo().targetSdkVersion <= Build.VERSION_CODES.R) {
2553 mUiAutomation.connect(flags);
2554 return mUiAutomation;
2555 }
2556 final long startUptime = SystemClock.uptimeMillis();
2557 try {
2558 mUiAutomation.connectWithTimeout(flags, CONNECT_TIMEOUT_MILLIS);
2559 return mUiAutomation;
2560 } catch (TimeoutException e) {
2561 final long waited = SystemClock.uptimeMillis() - startUptime;
2562 Log.e(TAG, "Unable to connect to UiAutomation. Waited for " + waited + " ms", e);
2563 mUiAutomation.destroy();
2564 mUiAutomation = null;
2565 }
2566 }
2567 return null;
2568 }
2569
2570 /**
2571 * Takes control of the execution of messages on the specified looper until
2572 * {@link TestLooperManager#release} is called.
2573 */
2574 @android.ravenwood.annotation.RavenwoodKeep
2575 public TestLooperManager acquireLooperManager(Looper looper) {
2576 checkInstrumenting("acquireLooperManager");
2577 return new TestLooperManager(looper);
2578 }
2579
2580 private final class InstrumentationThread extends Thread {
2581 public InstrumentationThread(String name) {
2582 super(name);
2583 }
2584 public void run() {
2585 try {
2586 Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_DISPLAY);
2587 } catch (RuntimeException e) {
2588 Log.w(TAG, "Exception setting priority of instrumentation thread "
2589 + Process.myTid(), e);
2590 }
2591 if (mAutomaticPerformanceSnapshots) {
2592 startPerformanceSnapshot();
2593 }
2594 onStart();
2595 }
2596 }
2597
2598 private static final class EmptyRunnable implements Runnable {
2599 public void run() {
2600 }
2601 }
2602
2603 private static final class SyncRunnable implements Runnable {
2604 private final Runnable mTarget;
2605 private boolean mComplete;
2606
2607 public SyncRunnable(Runnable target) {
2608 mTarget = target;
2609 }
2610
2611 public void run() {
2612 mTarget.run();
2613 synchronized (this) {
2614 mComplete = true;
2615 notifyAll();
2616 }
2617 }
2618
2619 public void waitForComplete() {
2620 synchronized (this) {
2621 while (!mComplete) {
2622 try {
2623 wait();
2624 } catch (InterruptedException e) {
2625 }
2626 }
2627 }
2628 }
2629 }
2630
2631 private static final class ActivityWaiter {
2632 public final Intent intent;
2633 public Activity activity;
2634
2635 public ActivityWaiter(Intent _intent) {
2636 intent = _intent;
2637 }
2638 }
2639
2640 private final class ActivityGoing implements MessageQueue.IdleHandler {
2641 private final ActivityWaiter mWaiter;
2642
2643 public ActivityGoing(ActivityWaiter waiter) {
2644 mWaiter = waiter;
2645 }
2646
2647 public final boolean queueIdle() {
2648 synchronized (mSync) {
2649 mWaitingActivities.remove(mWaiter);
2650 mSync.notifyAll();
2651 }
2652 return false;
2653 }
2654 }
2655
2656 private static final class Idler implements MessageQueue.IdleHandler {
2657 private final Runnable mCallback;
2658 private boolean mIdle;
2659
2660 public Idler(Runnable callback) {
2661 mCallback = callback;
2662 mIdle = false;
2663 }
2664
2665 public final boolean queueIdle() {
2666 if (mCallback != null) {
2667 mCallback.run();
2668 }
2669 synchronized (this) {
2670 mIdle = true;
2671 notifyAll();
2672 }
2673 return false;
2674 }
2675
2676 public void waitForIdle() {
2677 synchronized (this) {
2678 while (!mIdle) {
2679 try {
2680 wait();
2681 } catch (InterruptedException e) {
2682 }
2683 }
2684 }
2685 }
2686 }
2687}