blob: f263ec0a594973a1b1760ab08c482c443579f7b9 [file] [log] [blame]
Craig Mautner27084302013-03-25 08:05:25 -07001/*
2 * Copyright (C) 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server.am;
18
Craig Mautner6170f732013-04-02 13:05:23 -070019import static android.Manifest.permission.START_ANY_ACTIVITY;
20import static android.content.pm.PackageManager.PERMISSION_GRANTED;
Craig Mautner2420ead2013-04-01 17:13:20 -070021import static com.android.server.am.ActivityManagerService.localLOGV;
Craig Mautner23ac33b2013-04-01 16:26:35 -070022import static com.android.server.am.ActivityManagerService.DEBUG_CONFIGURATION;
Craig Mautner6170f732013-04-02 13:05:23 -070023import static com.android.server.am.ActivityManagerService.DEBUG_RESULTS;
Craig Mautner2420ead2013-04-01 17:13:20 -070024import static com.android.server.am.ActivityManagerService.DEBUG_SWITCH;
Craig Mautner8849a5e2013-04-02 16:41:03 -070025import static com.android.server.am.ActivityManagerService.DEBUG_TASKS;
26import static com.android.server.am.ActivityManagerService.DEBUG_USER_LEAVING;
Craig Mautner8d341ef2013-03-26 09:03:27 -070027import static com.android.server.am.ActivityManagerService.TAG;
28
Craig Mautner2420ead2013-04-01 17:13:20 -070029import android.app.Activity;
Craig Mautner23ac33b2013-04-01 16:26:35 -070030import android.app.ActivityManager;
31import android.app.ActivityOptions;
32import android.app.AppGlobals;
33import android.app.IApplicationThread;
Craig Mautner20e72272013-04-01 13:45:53 -070034import android.app.IThumbnailReceiver;
Craig Mautner23ac33b2013-04-01 16:26:35 -070035import android.app.PendingIntent;
Craig Mautner20e72272013-04-01 13:45:53 -070036import android.app.ActivityManager.RunningTaskInfo;
Craig Mautner23ac33b2013-04-01 16:26:35 -070037import android.app.IActivityManager.WaitResult;
Craig Mautner2420ead2013-04-01 17:13:20 -070038import android.app.ResultInfo;
Craig Mautner23ac33b2013-04-01 16:26:35 -070039import android.content.ComponentName;
Craig Mautner2219a1b2013-03-25 09:44:30 -070040import android.content.Context;
Craig Mautner23ac33b2013-04-01 16:26:35 -070041import android.content.IIntentSender;
Craig Mautner2219a1b2013-03-25 09:44:30 -070042import android.content.Intent;
Craig Mautner23ac33b2013-04-01 16:26:35 -070043import android.content.IntentSender;
Craig Mautner2219a1b2013-03-25 09:44:30 -070044import android.content.pm.ActivityInfo;
Craig Mautner23ac33b2013-04-01 16:26:35 -070045import android.content.pm.ApplicationInfo;
46import android.content.pm.PackageManager;
47import android.content.pm.ResolveInfo;
48import android.content.res.Configuration;
49import android.os.Binder;
Craig Mautner8d341ef2013-03-26 09:03:27 -070050import android.os.Bundle;
Craig Mautner23ac33b2013-04-01 16:26:35 -070051import android.os.IBinder;
Craig Mautner2219a1b2013-03-25 09:44:30 -070052import android.os.Looper;
Craig Mautner2420ead2013-04-01 17:13:20 -070053import android.os.Message;
Craig Mautner23ac33b2013-04-01 16:26:35 -070054import android.os.ParcelFileDescriptor;
Craig Mautner8d341ef2013-03-26 09:03:27 -070055import android.os.RemoteException;
Craig Mautner23ac33b2013-04-01 16:26:35 -070056import android.os.SystemClock;
Craig Mautner6170f732013-04-02 13:05:23 -070057import android.os.UserHandle;
Craig Mautner2420ead2013-04-01 17:13:20 -070058import android.util.EventLog;
Craig Mautner8d341ef2013-03-26 09:03:27 -070059import android.util.Slog;
Craig Mautner2219a1b2013-03-25 09:44:30 -070060
Craig Mautner23ac33b2013-04-01 16:26:35 -070061import com.android.internal.app.HeavyWeightSwitcherActivity;
Craig Mautner6170f732013-04-02 13:05:23 -070062import com.android.server.am.ActivityManagerService.PendingActivityLaunch;
Craig Mautner2420ead2013-04-01 17:13:20 -070063import com.android.server.am.ActivityStack.ActivityState;
Craig Mautner23ac33b2013-04-01 16:26:35 -070064
Craig Mautner8d341ef2013-03-26 09:03:27 -070065import java.io.FileDescriptor;
66import java.io.IOException;
Craig Mautner27084302013-03-25 08:05:25 -070067import java.io.PrintWriter;
Craig Mautner2219a1b2013-03-25 09:44:30 -070068import java.util.ArrayList;
Craig Mautner8d341ef2013-03-26 09:03:27 -070069import java.util.List;
Craig Mautner27084302013-03-25 08:05:25 -070070
71public class ActivityStackSupervisor {
Craig Mautner2420ead2013-04-01 17:13:20 -070072 static final boolean DEBUG_ADD_REMOVE = false;
73 static final boolean DEBUG_APP = false;
74 static final boolean DEBUG_SAVED_STATE = false;
75 static final boolean DEBUG_STATES = false;
76
Craig Mautner2219a1b2013-03-25 09:44:30 -070077 public static final int HOME_STACK_ID = 0;
Craig Mautner27084302013-03-25 08:05:25 -070078
79 final ActivityManagerService mService;
Craig Mautner2219a1b2013-03-25 09:44:30 -070080 final Context mContext;
81 final Looper mLooper;
Craig Mautner27084302013-03-25 08:05:25 -070082
83 /** Dismiss the keyguard after the next activity is displayed? */
84 private boolean mDismissKeyguardOnNextActivity = false;
85
Craig Mautner8d341ef2013-03-26 09:03:27 -070086 /** Identifier counter for all ActivityStacks */
87 private int mLastStackId = 0;
88
89 /** Task identifier that activities are currently being started in. Incremented each time a
90 * new task is created. */
91 private int mCurTaskId = 0;
92
Craig Mautner2420ead2013-04-01 17:13:20 -070093 /** The current user */
94 private int mCurrentUser;
95
Craig Mautner8d341ef2013-03-26 09:03:27 -070096 /** The stack containing the launcher app */
Craig Mautner2219a1b2013-03-25 09:44:30 -070097 private ActivityStack mHomeStack;
Craig Mautner20e72272013-04-01 13:45:53 -070098
99 /** The stack currently receiving input or launching the next activity */
Craig Mautner2219a1b2013-03-25 09:44:30 -0700100 private ActivityStack mMainStack;
Craig Mautner8d341ef2013-03-26 09:03:27 -0700101
102 /** All the non-launcher stacks */
Craig Mautner2219a1b2013-03-25 09:44:30 -0700103 private ArrayList<ActivityStack> mStacks = new ArrayList<ActivityStack>();
104
105 public ActivityStackSupervisor(ActivityManagerService service, Context context,
106 Looper looper) {
Craig Mautner27084302013-03-25 08:05:25 -0700107 mService = service;
Craig Mautner2219a1b2013-03-25 09:44:30 -0700108 mContext = context;
109 mLooper = looper;
110 }
111
Craig Mautner2420ead2013-04-01 17:13:20 -0700112 void init(int userId) {
113 mHomeStack = new ActivityStack(mService, mContext, mLooper, HOME_STACK_ID, this, userId);
Craig Mautner2219a1b2013-03-25 09:44:30 -0700114 setMainStack(mHomeStack);
Craig Mautner8d341ef2013-03-26 09:03:27 -0700115 mStacks.add(mHomeStack);
Craig Mautner27084302013-03-25 08:05:25 -0700116 }
117
118 void dismissKeyguard() {
119 if (mDismissKeyguardOnNextActivity) {
120 mDismissKeyguardOnNextActivity = false;
121 mService.mWindowManager.dismissKeyguard();
122 }
123 }
124
Craig Mautner20e72272013-04-01 13:45:53 -0700125 boolean isHomeStackMain() {
126 return mHomeStack == mMainStack;
127 }
128
Craig Mautner2219a1b2013-03-25 09:44:30 -0700129 boolean isMainStack(ActivityStack stack) {
130 return stack == mMainStack;
131 }
132
Craig Mautner20e72272013-04-01 13:45:53 -0700133 ActivityStack getMainStack() {
134 return mMainStack;
135 }
136
Craig Mautner2219a1b2013-03-25 09:44:30 -0700137 void setMainStack(ActivityStack stack) {
138 mMainStack = stack;
139 }
140
Craig Mautner27084302013-03-25 08:05:25 -0700141 void setDismissKeyguard(boolean dismiss) {
142 mDismissKeyguardOnNextActivity = dismiss;
143 }
144
Craig Mautner8d341ef2013-03-26 09:03:27 -0700145 TaskRecord anyTaskForIdLocked(int id) {
146 for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
147 ActivityStack stack = mStacks.get(stackNdx);
148 TaskRecord task = stack.taskForIdLocked(id);
149 if (task != null) {
150 return task;
151 }
152 }
153 return null;
154 }
155
Craig Mautner6170f732013-04-02 13:05:23 -0700156 ActivityRecord isInAnyStackLocked(IBinder token) {
157 for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
158 final ActivityRecord r = mStacks.get(stackNdx).isInStackLocked(token);
159 if (r != null) {
160 return r;
161 }
162 }
163 return null;
164 }
165
Craig Mautner8d341ef2013-03-26 09:03:27 -0700166 int getNextTaskId() {
167 do {
168 mCurTaskId++;
169 if (mCurTaskId <= 0) {
170 mCurTaskId = 1;
171 }
172 } while (anyTaskForIdLocked(mCurTaskId) != null);
173 return mCurTaskId;
174 }
175
Craig Mautner20e72272013-04-01 13:45:53 -0700176 boolean attachApplicationLocked(ProcessRecord app, boolean headless) throws Exception {
177 boolean didSomething = false;
178 final String processName = app.processName;
179 for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
180 final ActivityStack stack = mStacks.get(stackNdx);
181 ActivityRecord hr = stack.topRunningActivityLocked(null);
182 if (hr != null) {
183 if (hr.app == null && app.uid == hr.info.applicationInfo.uid
184 && processName.equals(hr.processName)) {
185 try {
186 if (headless) {
187 Slog.e(TAG, "Starting activities not supported on headless device: "
188 + hr);
Craig Mautner2420ead2013-04-01 17:13:20 -0700189 } else if (realStartActivityLocked(hr, app, true, true)) {
Craig Mautner20e72272013-04-01 13:45:53 -0700190 didSomething = true;
191 }
192 } catch (Exception e) {
193 Slog.w(TAG, "Exception in new application when starting activity "
194 + hr.intent.getComponent().flattenToShortString(), e);
195 throw e;
196 }
197 } else {
198 stack.ensureActivitiesVisibleLocked(hr, null, processName, 0);
199 }
200 }
201 }
202 return didSomething;
203 }
204
205 boolean allResumedActivitiesIdle() {
206 for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
Craig Mautnerdbcb31f2013-04-02 12:32:53 -0700207 final ActivityRecord resumedActivity = mStacks.get(stackNdx).mResumedActivity;
208 if (resumedActivity == null || !resumedActivity.idle) {
Craig Mautner20e72272013-04-01 13:45:53 -0700209 return false;
210 }
211 }
212 return true;
213 }
214
215 ActivityRecord getTasksLocked(int maxNum, IThumbnailReceiver receiver,
216 PendingThumbnailsRecord pending, List<RunningTaskInfo> list) {
217 ActivityRecord r = null;
218 final int numStacks = mStacks.size();
219 for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
220 final ActivityStack stack = mStacks.get(stackNdx);
221 final ActivityRecord ar =
222 stack.getTasksLocked(maxNum - list.size(), receiver, pending, list);
223 if (isMainStack(stack)) {
224 r = ar;
225 }
226 }
227 return r;
228 }
229
Craig Mautner23ac33b2013-04-01 16:26:35 -0700230 ActivityInfo resolveActivity(Intent intent, String resolvedType, int startFlags,
231 String profileFile, ParcelFileDescriptor profileFd, int userId) {
232 // Collect information about the target of the Intent.
233 ActivityInfo aInfo;
234 try {
235 ResolveInfo rInfo =
236 AppGlobals.getPackageManager().resolveIntent(
237 intent, resolvedType,
238 PackageManager.MATCH_DEFAULT_ONLY
239 | ActivityManagerService.STOCK_PM_FLAGS, userId);
240 aInfo = rInfo != null ? rInfo.activityInfo : null;
241 } catch (RemoteException e) {
242 aInfo = null;
243 }
244
245 if (aInfo != null) {
246 // Store the found target back into the intent, because now that
247 // we have it we never want to do this again. For example, if the
248 // user navigates back to this point in the history, we should
249 // always restart the exact same activity.
250 intent.setComponent(new ComponentName(
251 aInfo.applicationInfo.packageName, aInfo.name));
252
253 // Don't debug things in the system process
254 if ((startFlags&ActivityManager.START_FLAG_DEBUG) != 0) {
255 if (!aInfo.processName.equals("system")) {
256 mService.setDebugApp(aInfo.processName, true, false);
257 }
258 }
259
260 if ((startFlags&ActivityManager.START_FLAG_OPENGL_TRACES) != 0) {
261 if (!aInfo.processName.equals("system")) {
262 mService.setOpenGlTraceApp(aInfo.applicationInfo, aInfo.processName);
263 }
264 }
265
266 if (profileFile != null) {
267 if (!aInfo.processName.equals("system")) {
268 mService.setProfileApp(aInfo.applicationInfo, aInfo.processName,
269 profileFile, profileFd,
270 (startFlags&ActivityManager.START_FLAG_AUTO_STOP_PROFILER) != 0);
271 }
272 }
273 }
274 return aInfo;
275 }
276
Craig Mautner2219a1b2013-03-25 09:44:30 -0700277 void startHomeActivity(Intent intent, ActivityInfo aInfo) {
Craig Mautner6170f732013-04-02 13:05:23 -0700278 startActivityLocked(null, intent, null, aInfo, null, null, 0, 0, 0, null, 0,
Craig Mautner2219a1b2013-03-25 09:44:30 -0700279 null, false, null);
Craig Mautner8d341ef2013-03-26 09:03:27 -0700280 }
281
Craig Mautner23ac33b2013-04-01 16:26:35 -0700282 final int startActivityMayWait(IApplicationThread caller, int callingUid,
283 String callingPackage, Intent intent, String resolvedType, IBinder resultTo,
284 String resultWho, int requestCode, int startFlags, String profileFile,
285 ParcelFileDescriptor profileFd, WaitResult outResult, Configuration config,
286 Bundle options, int userId) {
287 // Refuse possible leaked file descriptors
288 if (intent != null && intent.hasFileDescriptors()) {
289 throw new IllegalArgumentException("File descriptors passed in Intent");
290 }
291 boolean componentSpecified = intent.getComponent() != null;
292
293 // Don't modify the client's object!
294 intent = new Intent(intent);
295
296 // Collect information about the target of the Intent.
297 ActivityInfo aInfo = resolveActivity(intent, resolvedType, startFlags,
298 profileFile, profileFd, userId);
299
300 synchronized (mService) {
301 int callingPid;
302 if (callingUid >= 0) {
303 callingPid = -1;
304 } else if (caller == null) {
305 callingPid = Binder.getCallingPid();
306 callingUid = Binder.getCallingUid();
307 } else {
308 callingPid = callingUid = -1;
309 }
310
311 mMainStack.mConfigWillChange = config != null
312 && mService.mConfiguration.diff(config) != 0;
313 if (DEBUG_CONFIGURATION) Slog.v(TAG,
314 "Starting activity when config will change = " + mMainStack.mConfigWillChange);
315
316 final long origId = Binder.clearCallingIdentity();
317
318 if (aInfo != null &&
319 (aInfo.applicationInfo.flags&ApplicationInfo.FLAG_CANT_SAVE_STATE) != 0) {
320 // This may be a heavy-weight process! Check to see if we already
321 // have another, different heavy-weight process running.
322 if (aInfo.processName.equals(aInfo.applicationInfo.packageName)) {
323 if (mService.mHeavyWeightProcess != null &&
324 (mService.mHeavyWeightProcess.info.uid != aInfo.applicationInfo.uid ||
325 !mService.mHeavyWeightProcess.processName.equals(aInfo.processName))) {
326 int realCallingPid = callingPid;
327 int realCallingUid = callingUid;
328 if (caller != null) {
329 ProcessRecord callerApp = mService.getRecordForAppLocked(caller);
330 if (callerApp != null) {
331 realCallingPid = callerApp.pid;
332 realCallingUid = callerApp.info.uid;
333 } else {
334 Slog.w(TAG, "Unable to find app for caller " + caller
335 + " (pid=" + realCallingPid + ") when starting: "
336 + intent.toString());
337 ActivityOptions.abort(options);
338 return ActivityManager.START_PERMISSION_DENIED;
339 }
340 }
341
342 IIntentSender target = mService.getIntentSenderLocked(
343 ActivityManager.INTENT_SENDER_ACTIVITY, "android",
344 realCallingUid, userId, null, null, 0, new Intent[] { intent },
345 new String[] { resolvedType }, PendingIntent.FLAG_CANCEL_CURRENT
346 | PendingIntent.FLAG_ONE_SHOT, null);
347
348 Intent newIntent = new Intent();
349 if (requestCode >= 0) {
350 // Caller is requesting a result.
351 newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_HAS_RESULT, true);
352 }
353 newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_INTENT,
354 new IntentSender(target));
355 if (mService.mHeavyWeightProcess.activities.size() > 0) {
356 ActivityRecord hist = mService.mHeavyWeightProcess.activities.get(0);
357 newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_CUR_APP,
358 hist.packageName);
359 newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_CUR_TASK,
360 hist.task.taskId);
361 }
362 newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_NEW_APP,
363 aInfo.packageName);
364 newIntent.setFlags(intent.getFlags());
365 newIntent.setClassName("android",
366 HeavyWeightSwitcherActivity.class.getName());
367 intent = newIntent;
368 resolvedType = null;
369 caller = null;
370 callingUid = Binder.getCallingUid();
371 callingPid = Binder.getCallingPid();
372 componentSpecified = true;
373 try {
374 ResolveInfo rInfo =
375 AppGlobals.getPackageManager().resolveIntent(
376 intent, null,
377 PackageManager.MATCH_DEFAULT_ONLY
378 | ActivityManagerService.STOCK_PM_FLAGS, userId);
379 aInfo = rInfo != null ? rInfo.activityInfo : null;
380 aInfo = mService.getActivityInfoForUser(aInfo, userId);
381 } catch (RemoteException e) {
382 aInfo = null;
383 }
384 }
385 }
386 }
387
Craig Mautner6170f732013-04-02 13:05:23 -0700388 int res = startActivityLocked(caller, intent, resolvedType,
Craig Mautner23ac33b2013-04-01 16:26:35 -0700389 aInfo, resultTo, resultWho, requestCode, callingPid, callingUid,
390 callingPackage, startFlags, options, componentSpecified, null);
391
392 if (mMainStack.mConfigWillChange) {
393 // If the caller also wants to switch to a new configuration,
394 // do so now. This allows a clean switch, as we are waiting
395 // for the current activity to pause (so we will not destroy
396 // it), and have not yet started the next activity.
397 mService.enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
398 "updateConfiguration()");
399 mMainStack.mConfigWillChange = false;
400 if (DEBUG_CONFIGURATION) Slog.v(TAG,
401 "Updating to new configuration after starting activity.");
402 mService.updateConfigurationLocked(config, null, false, false);
403 }
404
405 Binder.restoreCallingIdentity(origId);
406
407 if (outResult != null) {
408 outResult.result = res;
409 if (res == ActivityManager.START_SUCCESS) {
410 mMainStack.mWaitingActivityLaunched.add(outResult);
411 do {
412 try {
413 mService.wait();
414 } catch (InterruptedException e) {
415 }
416 } while (!outResult.timeout && outResult.who == null);
417 } else if (res == ActivityManager.START_TASK_TO_FRONT) {
418 ActivityRecord r = mMainStack.topRunningActivityLocked(null);
419 if (r.nowVisible) {
420 outResult.timeout = false;
421 outResult.who = new ComponentName(r.info.packageName, r.info.name);
422 outResult.totalTime = 0;
423 outResult.thisTime = 0;
424 } else {
425 outResult.thisTime = SystemClock.uptimeMillis();
426 mMainStack.mWaitingActivityVisible.add(outResult);
427 do {
428 try {
429 mService.wait();
430 } catch (InterruptedException e) {
431 }
432 } while (!outResult.timeout && outResult.who == null);
433 }
434 }
435 }
436
437 return res;
438 }
439 }
440
441 final int startActivities(IApplicationThread caller, int callingUid, String callingPackage,
442 Intent[] intents, String[] resolvedTypes, IBinder resultTo,
443 Bundle options, int userId) {
444 if (intents == null) {
445 throw new NullPointerException("intents is null");
446 }
447 if (resolvedTypes == null) {
448 throw new NullPointerException("resolvedTypes is null");
449 }
450 if (intents.length != resolvedTypes.length) {
451 throw new IllegalArgumentException("intents are length different than resolvedTypes");
452 }
453
454 ActivityRecord[] outActivity = new ActivityRecord[1];
455
456 int callingPid;
457 if (callingUid >= 0) {
458 callingPid = -1;
459 } else if (caller == null) {
460 callingPid = Binder.getCallingPid();
461 callingUid = Binder.getCallingUid();
462 } else {
463 callingPid = callingUid = -1;
464 }
465 final long origId = Binder.clearCallingIdentity();
466 try {
467 synchronized (mService) {
468
469 for (int i=0; i<intents.length; i++) {
470 Intent intent = intents[i];
471 if (intent == null) {
472 continue;
473 }
474
475 // Refuse possible leaked file descriptors
476 if (intent != null && intent.hasFileDescriptors()) {
477 throw new IllegalArgumentException("File descriptors passed in Intent");
478 }
479
480 boolean componentSpecified = intent.getComponent() != null;
481
482 // Don't modify the client's object!
483 intent = new Intent(intent);
484
485 // Collect information about the target of the Intent.
486 ActivityInfo aInfo = resolveActivity(intent, resolvedTypes[i],
487 0, null, null, userId);
488 // TODO: New, check if this is correct
489 aInfo = mService.getActivityInfoForUser(aInfo, userId);
490
491 if (aInfo != null &&
492 (aInfo.applicationInfo.flags & ApplicationInfo.FLAG_CANT_SAVE_STATE)
493 != 0) {
494 throw new IllegalArgumentException(
495 "FLAG_CANT_SAVE_STATE not supported here");
496 }
497
498 Bundle theseOptions;
499 if (options != null && i == intents.length-1) {
500 theseOptions = options;
501 } else {
502 theseOptions = null;
503 }
Craig Mautner6170f732013-04-02 13:05:23 -0700504 int res = startActivityLocked(caller, intent, resolvedTypes[i],
Craig Mautner23ac33b2013-04-01 16:26:35 -0700505 aInfo, resultTo, null, -1, callingPid, callingUid, callingPackage,
506 0, theseOptions, componentSpecified, outActivity);
507 if (res < 0) {
508 return res;
509 }
510
511 resultTo = outActivity[0] != null ? outActivity[0].appToken : null;
512 }
513 }
514 } finally {
515 Binder.restoreCallingIdentity(origId);
516 }
517
518 return ActivityManager.START_SUCCESS;
519 }
520
Craig Mautner2420ead2013-04-01 17:13:20 -0700521 final boolean realStartActivityLocked(ActivityRecord r,
522 ProcessRecord app, boolean andResume, boolean checkConfig)
523 throws RemoteException {
524
525 r.startFreezingScreenLocked(app, 0);
526 mService.mWindowManager.setAppVisibility(r.appToken, true);
527
528 // schedule launch ticks to collect information about slow apps.
529 r.startLaunchTickingLocked();
530
531 // Have the window manager re-evaluate the orientation of
532 // the screen based on the new activity order. Note that
533 // as a result of this, it can call back into the activity
534 // manager with a new orientation. We don't care about that,
535 // because the activity is not currently running so we are
536 // just restarting it anyway.
537 if (checkConfig) {
538 Configuration config = mService.mWindowManager.updateOrientationFromAppTokens(
539 mService.mConfiguration,
540 r.mayFreezeScreenLocked(app) ? r.appToken : null);
541 mService.updateConfigurationLocked(config, r, false, false);
542 }
543
544 r.app = app;
545 app.waitingToKill = null;
546 r.launchCount++;
547 r.lastLaunchTime = SystemClock.uptimeMillis();
548
549 if (localLOGV) Slog.v(TAG, "Launching: " + r);
550
551 int idx = app.activities.indexOf(r);
552 if (idx < 0) {
553 app.activities.add(r);
554 }
555 mService.updateLruProcessLocked(app, true);
556
557 final ActivityStack stack = r.task.stack;
558 try {
559 if (app.thread == null) {
560 throw new RemoteException();
561 }
562 List<ResultInfo> results = null;
563 List<Intent> newIntents = null;
564 if (andResume) {
565 results = r.results;
566 newIntents = r.newIntents;
567 }
568 if (DEBUG_SWITCH) Slog.v(TAG, "Launching: " + r
569 + " icicle=" + r.icicle
570 + " with results=" + results + " newIntents=" + newIntents
571 + " andResume=" + andResume);
572 if (andResume) {
573 EventLog.writeEvent(EventLogTags.AM_RESTART_ACTIVITY,
574 r.userId, System.identityHashCode(r),
575 r.task.taskId, r.shortComponentName);
576 }
577 if (r.isHomeActivity) {
578 mService.mHomeProcess = app;
579 }
580 mService.ensurePackageDexOpt(r.intent.getComponent().getPackageName());
581 r.sleeping = false;
582 r.forceNewConfig = false;
583 mService.showAskCompatModeDialogLocked(r);
584 r.compat = mService.compatibilityInfoForPackageLocked(r.info.applicationInfo);
585 String profileFile = null;
586 ParcelFileDescriptor profileFd = null;
587 boolean profileAutoStop = false;
588 if (mService.mProfileApp != null && mService.mProfileApp.equals(app.processName)) {
589 if (mService.mProfileProc == null || mService.mProfileProc == app) {
590 mService.mProfileProc = app;
591 profileFile = mService.mProfileFile;
592 profileFd = mService.mProfileFd;
593 profileAutoStop = mService.mAutoStopProfiler;
594 }
595 }
596 app.hasShownUi = true;
597 app.pendingUiClean = true;
598 if (profileFd != null) {
599 try {
600 profileFd = profileFd.dup();
601 } catch (IOException e) {
602 if (profileFd != null) {
603 try {
604 profileFd.close();
605 } catch (IOException o) {
606 }
607 profileFd = null;
608 }
609 }
610 }
611 app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
612 System.identityHashCode(r), r.info,
613 new Configuration(mService.mConfiguration),
614 r.compat, r.icicle, results, newIntents, !andResume,
615 mService.isNextTransitionForward(), profileFile, profileFd,
616 profileAutoStop);
617
618 if ((app.info.flags&ApplicationInfo.FLAG_CANT_SAVE_STATE) != 0) {
619 // This may be a heavy-weight process! Note that the package
620 // manager will ensure that only activity can run in the main
621 // process of the .apk, which is the only thing that will be
622 // considered heavy-weight.
623 if (app.processName.equals(app.info.packageName)) {
624 if (mService.mHeavyWeightProcess != null
625 && mService.mHeavyWeightProcess != app) {
626 Slog.w(TAG, "Starting new heavy weight process " + app
627 + " when already running "
628 + mService.mHeavyWeightProcess);
629 }
630 mService.mHeavyWeightProcess = app;
631 Message msg = mService.mHandler.obtainMessage(
632 ActivityManagerService.POST_HEAVY_NOTIFICATION_MSG);
633 msg.obj = r;
634 mService.mHandler.sendMessage(msg);
635 }
636 }
637
638 } catch (RemoteException e) {
639 if (r.launchFailed) {
640 // This is the second time we failed -- finish activity
641 // and give up.
642 Slog.e(TAG, "Second failure launching "
643 + r.intent.getComponent().flattenToShortString()
644 + ", giving up", e);
645 mService.appDiedLocked(app, app.pid, app.thread);
646 stack.requestFinishActivityLocked(r.appToken, Activity.RESULT_CANCELED, null,
647 "2nd-crash", false);
648 return false;
649 }
650
651 // This is the first time we failed -- restart process and
652 // retry.
653 app.activities.remove(r);
654 throw e;
655 }
656
657 r.launchFailed = false;
658 if (stack.updateLRUListLocked(r)) {
659 Slog.w(TAG, "Activity " + r
660 + " being launched, but already in LRU list");
661 }
662
663 if (andResume) {
664 // As part of the process of launching, ActivityThread also performs
665 // a resume.
666 stack.minimalResumeActivityLocked(r);
667 } else {
668 // This activity is not starting in the resumed state... which
669 // should look like we asked it to pause+stop (but remain visible),
670 // and it has done so and reported back the current icicle and
671 // other state.
672 if (DEBUG_STATES) Slog.v(TAG, "Moving to STOPPED: " + r
673 + " (starting in stopped state)");
674 r.state = ActivityState.STOPPED;
675 r.stopped = true;
676 }
677
678 // Launch the new version setup screen if needed. We do this -after-
679 // launching the initial activity (that is, home), so that it can have
680 // a chance to initialize itself while in the background, making the
681 // switch back to it faster and look better.
682 if (isMainStack(stack)) {
683 mService.startSetupActivityLocked();
684 }
685
686 return true;
687 }
688
Craig Mautnere79d42682013-04-01 19:01:53 -0700689 void startSpecificActivityLocked(ActivityRecord r,
690 boolean andResume, boolean checkConfig) {
691 // Is this activity's application already running?
692 ProcessRecord app = mService.getProcessRecordLocked(r.processName,
693 r.info.applicationInfo.uid);
694
695 r.task.stack.setLaunchTime(r);
696
697 if (app != null && app.thread != null) {
698 try {
699 app.addPackage(r.info.packageName);
700 realStartActivityLocked(r, app, andResume, checkConfig);
701 return;
702 } catch (RemoteException e) {
703 Slog.w(TAG, "Exception when starting activity "
704 + r.intent.getComponent().flattenToShortString(), e);
705 }
706
707 // If a dead object exception was thrown -- fall through to
708 // restart the application.
709 }
710
711 mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
712 "activity", r.intent.getComponent(), false, false);
713 }
714
Craig Mautner6170f732013-04-02 13:05:23 -0700715 final int startActivityLocked(IApplicationThread caller,
716 Intent intent, String resolvedType, ActivityInfo aInfo, IBinder resultTo,
717 String resultWho, int requestCode,
718 int callingPid, int callingUid, String callingPackage, int startFlags, Bundle options,
719 boolean componentSpecified, ActivityRecord[] outActivity) {
720 int err = ActivityManager.START_SUCCESS;
721
722 ProcessRecord callerApp = null;
723 if (caller != null) {
724 callerApp = mService.getRecordForAppLocked(caller);
725 if (callerApp != null) {
726 callingPid = callerApp.pid;
727 callingUid = callerApp.info.uid;
728 } else {
729 Slog.w(TAG, "Unable to find app for caller " + caller
730 + " (pid=" + callingPid + ") when starting: "
731 + intent.toString());
732 err = ActivityManager.START_PERMISSION_DENIED;
733 }
734 }
735
736 if (err == ActivityManager.START_SUCCESS) {
737 final int userId = aInfo != null ? UserHandle.getUserId(aInfo.applicationInfo.uid) : 0;
738 Slog.i(TAG, "START u" + userId + " {" + intent.toShortString(true, true, true, false)
739 + "} from pid " + (callerApp != null ? callerApp.pid : callingPid));
740 }
741
742 ActivityRecord sourceRecord = null;
743 ActivityRecord resultRecord = null;
744 if (resultTo != null) {
745 sourceRecord = isInAnyStackLocked(resultTo);
746 if (DEBUG_RESULTS) Slog.v(
747 TAG, "Will send result to " + resultTo + " " + sourceRecord);
748 if (sourceRecord != null) {
749 if (requestCode >= 0 && !sourceRecord.finishing) {
750 resultRecord = sourceRecord;
751 }
752 }
753 }
754 ActivityStack resultStack = resultRecord == null ? null : resultRecord.task.stack;
755
756 int launchFlags = intent.getFlags();
757
758 if ((launchFlags&Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0
759 && sourceRecord != null) {
760 // Transfer the result target from the source activity to the new
761 // one being started, including any failures.
762 if (requestCode >= 0) {
763 ActivityOptions.abort(options);
764 return ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT;
765 }
766 resultRecord = sourceRecord.resultTo;
767 resultWho = sourceRecord.resultWho;
768 requestCode = sourceRecord.requestCode;
769 sourceRecord.resultTo = null;
770 if (resultRecord != null) {
771 resultRecord.removeResultsLocked(
772 sourceRecord, resultWho, requestCode);
773 }
774 }
775
776 if (err == ActivityManager.START_SUCCESS && intent.getComponent() == null) {
777 // We couldn't find a class that can handle the given Intent.
778 // That's the end of that!
779 err = ActivityManager.START_INTENT_NOT_RESOLVED;
780 }
781
782 if (err == ActivityManager.START_SUCCESS && aInfo == null) {
783 // We couldn't find the specific class specified in the Intent.
784 // Also the end of the line.
785 err = ActivityManager.START_CLASS_NOT_FOUND;
786 }
787
788 if (err != ActivityManager.START_SUCCESS) {
789 if (resultRecord != null) {
790 resultStack.sendActivityResultLocked(-1,
791 resultRecord, resultWho, requestCode,
792 Activity.RESULT_CANCELED, null);
793 }
794 setDismissKeyguard(false);
795 ActivityOptions.abort(options);
796 return err;
797 }
798
799 final int startAnyPerm = mService.checkPermission(
800 START_ANY_ACTIVITY, callingPid, callingUid);
801 final int componentPerm = mService.checkComponentPermission(aInfo.permission, callingPid,
802 callingUid, aInfo.applicationInfo.uid, aInfo.exported);
803 if (startAnyPerm != PERMISSION_GRANTED && componentPerm != PERMISSION_GRANTED) {
804 if (resultRecord != null) {
805 resultStack.sendActivityResultLocked(-1,
806 resultRecord, resultWho, requestCode,
807 Activity.RESULT_CANCELED, null);
808 }
809 setDismissKeyguard(false);
810 String msg;
811 if (!aInfo.exported) {
812 msg = "Permission Denial: starting " + intent.toString()
813 + " from " + callerApp + " (pid=" + callingPid
814 + ", uid=" + callingUid + ")"
815 + " not exported from uid " + aInfo.applicationInfo.uid;
816 } else {
817 msg = "Permission Denial: starting " + intent.toString()
818 + " from " + callerApp + " (pid=" + callingPid
819 + ", uid=" + callingUid + ")"
820 + " requires " + aInfo.permission;
821 }
822 Slog.w(TAG, msg);
823 throw new SecurityException(msg);
824 }
825
Ben Gruver5e207332013-04-03 17:41:37 -0700826 boolean abort = !mService.mIntentFirewall.checkStartActivity(intent, 2596
827 callerApp==null?null:callerApp.info, callingPackage, callingUid, callingPid, 2597
828 resolvedType, aInfo);
829
Craig Mautner6170f732013-04-02 13:05:23 -0700830 if (mService.mController != null) {
Craig Mautner6170f732013-04-02 13:05:23 -0700831 try {
832 // The Intent we give to the watcher has the extra data
833 // stripped off, since it can contain private information.
834 Intent watchIntent = intent.cloneFilter();
Ben Gruver5e207332013-04-03 17:41:37 -0700835 abort |= !mService.mController.activityStarting(watchIntent,
Craig Mautner6170f732013-04-02 13:05:23 -0700836 aInfo.applicationInfo.packageName);
837 } catch (RemoteException e) {
838 mService.mController = null;
839 }
Ben Gruver5e207332013-04-03 17:41:37 -0700840 }
Craig Mautner6170f732013-04-02 13:05:23 -0700841
Ben Gruver5e207332013-04-03 17:41:37 -0700842 if (abort) {
843 if (resultRecord != null) {
844 resultStack.sendActivityResultLocked(-1, resultRecord, resultWho, requestCode,
Craig Mautner6170f732013-04-02 13:05:23 -0700845 Activity.RESULT_CANCELED, null);
Craig Mautner6170f732013-04-02 13:05:23 -0700846 }
Ben Gruver5e207332013-04-03 17:41:37 -0700847 // We pretend to the caller that it was really started, but
848 // they will just get a cancel result.
849 setDismissKeyguard(false);
850 ActivityOptions.abort(options);
851 return ActivityManager.START_SUCCESS;
Craig Mautner6170f732013-04-02 13:05:23 -0700852 }
853
854 ActivityRecord r = new ActivityRecord(mService, callerApp, callingUid, callingPackage,
855 intent, resolvedType, aInfo, mService.mConfiguration,
856 resultRecord, resultWho, requestCode, componentSpecified);
857 if (outActivity != null) {
858 outActivity[0] = r;
859 }
860
861 if (mMainStack.mResumedActivity == null
862 || mMainStack.mResumedActivity.info.applicationInfo.uid != callingUid) {
863 if (!mService.checkAppSwitchAllowedLocked(callingPid, callingUid, "Activity start")) {
864 PendingActivityLaunch pal =
865 new PendingActivityLaunch(r, sourceRecord, startFlags, mMainStack);
866 mService.mPendingActivityLaunches.add(pal);
867 setDismissKeyguard(false);
868 ActivityOptions.abort(options);
869 return ActivityManager.START_SWITCHES_CANCELED;
870 }
871 }
872
873 if (mService.mDidAppSwitch) {
874 // This is the second allowed switch since we stopped switches,
875 // so now just generally allow switches. Use case: user presses
876 // home (switches disabled, switch to home, mDidAppSwitch now true);
877 // user taps a home icon (coming from home so allowed, we hit here
878 // and now allow anyone to switch again).
879 mService.mAppSwitchesAllowedTime = 0;
880 } else {
881 mService.mDidAppSwitch = true;
882 }
883
884 mService.doPendingActivityLaunchesLocked(false);
885
Craig Mautner8849a5e2013-04-02 16:41:03 -0700886 err = startActivityUncheckedLocked(r, sourceRecord, startFlags, true, options);
Craig Mautner6170f732013-04-02 13:05:23 -0700887 if (mMainStack.mPausingActivity == null) {
888 // Someone asked to have the keyguard dismissed on the next
889 // activity start, but we are not actually doing an activity
890 // switch... just dismiss the keyguard now, because we
891 // probably want to see whatever is behind it.
892 dismissKeyguard();
893 }
894 return err;
895 }
896
Craig Mautner8849a5e2013-04-02 16:41:03 -0700897 final int startActivityUncheckedLocked(ActivityRecord r,
898 ActivityRecord sourceRecord, int startFlags, boolean doResume,
899 Bundle options) {
900 final Intent intent = r.intent;
901 final int callingUid = r.launchedFromUid;
902
903 int launchFlags = intent.getFlags();
904
905 final ActivityStack stack = mMainStack;
906 ActivityStack targetStack = mMainStack;
907
908 // We'll invoke onUserLeaving before onPause only if the launching
909 // activity did not explicitly state that this is an automated launch.
910 targetStack.mUserLeaving = (launchFlags&Intent.FLAG_ACTIVITY_NO_USER_ACTION) == 0;
911 if (DEBUG_USER_LEAVING) Slog.v(TAG,
912 "startActivity() => mUserLeaving=" + targetStack.mUserLeaving);
913
914 // If the caller has asked not to resume at this point, we make note
915 // of this in the record so that we can skip it when trying to find
916 // the top running activity.
917 if (!doResume) {
918 r.delayedResume = true;
919 }
920
921 ActivityRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP) != 0 ? r : null;
922
923 // If the onlyIfNeeded flag is set, then we can do this if the activity
924 // being launched is the same as the one making the call... or, as
925 // a special case, if we do not know the caller then we count the
926 // current top activity as the caller.
927 if ((startFlags&ActivityManager.START_FLAG_ONLY_IF_NEEDED) != 0) {
928 ActivityRecord checkedCaller = sourceRecord;
929 if (checkedCaller == null) {
930 checkedCaller = targetStack.topRunningNonDelayedActivityLocked(notTop);
931 }
932 if (!checkedCaller.realActivity.equals(r.realActivity)) {
933 // Caller is not the same as launcher, so always needed.
934 startFlags &= ~ActivityManager.START_FLAG_ONLY_IF_NEEDED;
935 }
936 }
937
938 if (sourceRecord == null) {
939 // This activity is not being started from another... in this
940 // case we -always- start a new task.
941 if ((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
942 Slog.w(TAG, "startActivity called from non-Activity context; forcing Intent.FLAG_ACTIVITY_NEW_TASK for: "
943 + intent);
944 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
945 }
946 } else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
947 // The original activity who is starting us is running as a single
948 // instance... this new activity it is starting must go on its
949 // own task.
950 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
951 } else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE
952 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
953 // The activity being started is a single instance... it always
954 // gets launched into its own task.
955 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
956 }
957
958 if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
959 // For whatever reason this activity is being launched into a new
960 // task... yet the caller has requested a result back. Well, that
961 // is pretty messed up, so instead immediately send back a cancel
962 // and let the new task continue launched as normal without a
963 // dependency on its originator.
964 Slog.w(TAG, "Activity is launching as a new task, so cancelling activity result.");
965 r.resultTo.task.stack.sendActivityResultLocked(-1,
966 r.resultTo, r.resultWho, r.requestCode,
967 Activity.RESULT_CANCELED, null);
968 r.resultTo = null;
969 }
970
971 boolean addingToTask = false;
972 boolean movedHome = false;
973 TaskRecord reuseTask = null;
974 if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
975 (launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
976 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
977 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
978 // If bring to front is requested, and no result is requested, and
979 // we can find a task that was started with this same
980 // component, then instead of launching bring that one to the front.
981 if (r.resultTo == null) {
982 // See if there is a task to bring to the front. If this is
983 // a SINGLE_INSTANCE activity, there can be one and only one
984 // instance of it in the history, and it is always in its own
985 // unique task, so we do a special search.
986 ActivityRecord intentActivity = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE
987 ? findTaskLocked(intent, r.info)
988 : findActivityLocked(intent, r.info);
989 if (intentActivity != null) {
990 targetStack = intentActivity.task.stack;
991 if (intentActivity.task.intent == null) {
992 // This task was started because of movement of
993 // the activity based on affinity... now that we
994 // are actually launching it, we can assign the
995 // base intent.
996 intentActivity.task.setIntent(intent, r.info);
997 }
998 // If the target task is not in the front, then we need
999 // to bring it to the front... except... well, with
1000 // SINGLE_TASK_LAUNCH it's not entirely clear. We'd like
1001 // to have the same behavior as if a new instance was
1002 // being started, which means not bringing it to the front
1003 // if the caller is not itself in the front.
1004 ActivityRecord curTop = targetStack.topRunningNonDelayedActivityLocked(notTop);
1005 if (curTop != null && curTop.task != intentActivity.task) {
1006 r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
1007 boolean callerAtFront = sourceRecord == null
1008 || curTop.task == sourceRecord.task;
1009 if (callerAtFront) {
1010 // We really do want to push this one into the
1011 // user's face, right now.
1012 movedHome = true;
1013 targetStack.moveHomeToFrontFromLaunchLocked(launchFlags);
1014 targetStack.moveTaskToFrontLocked(intentActivity.task, r, options);
1015 options = null;
1016 }
1017 }
1018 // If the caller has requested that the target task be
1019 // reset, then do so.
1020 if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
1021 intentActivity = targetStack.resetTaskIfNeededLocked(intentActivity, r);
1022 }
1023 if ((startFlags&ActivityManager.START_FLAG_ONLY_IF_NEEDED) != 0) {
1024 // We don't need to start a new activity, and
1025 // the client said not to do anything if that
1026 // is the case, so this is it! And for paranoia, make
1027 // sure we have correctly resumed the top activity.
1028 if (doResume) {
1029 targetStack.resumeTopActivityLocked(null, options);
1030 } else {
1031 ActivityOptions.abort(options);
1032 }
1033 return ActivityManager.START_RETURN_INTENT_TO_CALLER;
1034 }
1035 if ((launchFlags &
1036 (Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_CLEAR_TASK))
1037 == (Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_CLEAR_TASK)) {
1038 // The caller has requested to completely replace any
1039 // existing task with its new activity. Well that should
1040 // not be too hard...
1041 reuseTask = intentActivity.task;
1042 reuseTask.performClearTaskLocked();
1043 reuseTask.setIntent(r.intent, r.info);
1044 } else if ((launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0
1045 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
1046 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
1047 // In this situation we want to remove all activities
1048 // from the task up to the one being started. In most
1049 // cases this means we are resetting the task to its
1050 // initial state.
1051 ActivityRecord top =
1052 intentActivity.task.performClearTaskLocked(r, launchFlags);
1053 if (top != null) {
1054 if (top.frontOfTask) {
1055 // Activity aliases may mean we use different
1056 // intents for the top activity, so make sure
1057 // the task now has the identity of the new
1058 // intent.
1059 top.task.setIntent(r.intent, r.info);
1060 }
1061 ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT,
1062 r, top.task);
1063 top.deliverNewIntentLocked(callingUid, r.intent);
1064 } else {
1065 // A special case: we need to
1066 // start the activity because it is not currently
1067 // running, and the caller has asked to clear the
1068 // current task to have this activity at the top.
1069 addingToTask = true;
1070 // Now pretend like this activity is being started
1071 // by the top of its task, so it is put in the
1072 // right place.
1073 sourceRecord = intentActivity;
1074 }
1075 } else if (r.realActivity.equals(intentActivity.task.realActivity)) {
1076 // In this case the top activity on the task is the
1077 // same as the one being launched, so we take that
1078 // as a request to bring the task to the foreground.
1079 // If the top activity in the task is the root
1080 // activity, deliver this new intent to it if it
1081 // desires.
1082 if (((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
1083 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP)
1084 && intentActivity.realActivity.equals(r.realActivity)) {
1085 ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, r,
1086 intentActivity.task);
1087 if (intentActivity.frontOfTask) {
1088 intentActivity.task.setIntent(r.intent, r.info);
1089 }
1090 intentActivity.deliverNewIntentLocked(callingUid, r.intent);
1091 } else if (!r.intent.filterEquals(intentActivity.task.intent)) {
1092 // In this case we are launching the root activity
1093 // of the task, but with a different intent. We
1094 // should start a new instance on top.
1095 addingToTask = true;
1096 sourceRecord = intentActivity;
1097 }
1098 } else if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) {
1099 // In this case an activity is being launched in to an
1100 // existing task, without resetting that task. This
1101 // is typically the situation of launching an activity
1102 // from a notification or shortcut. We want to place
1103 // the new activity on top of the current task.
1104 addingToTask = true;
1105 sourceRecord = intentActivity;
1106 } else if (!intentActivity.task.rootWasReset) {
1107 // In this case we are launching in to an existing task
1108 // that has not yet been started from its front door.
1109 // The current task has been brought to the front.
1110 // Ideally, we'd probably like to place this new task
1111 // at the bottom of its stack, but that's a little hard
1112 // to do with the current organization of the code so
1113 // for now we'll just drop it.
1114 intentActivity.task.setIntent(r.intent, r.info);
1115 }
1116 if (!addingToTask && reuseTask == null) {
1117 // We didn't do anything... but it was needed (a.k.a., client
1118 // don't use that intent!) And for paranoia, make
1119 // sure we have correctly resumed the top activity.
1120 if (doResume) {
1121 stack.resumeTopActivityLocked(null, options);
1122 } else {
1123 ActivityOptions.abort(options);
1124 }
1125 return ActivityManager.START_TASK_TO_FRONT;
1126 }
1127 }
1128 }
1129 }
1130
1131 //String uri = r.intent.toURI();
1132 //Intent intent2 = new Intent(uri);
1133 //Slog.i(TAG, "Given intent: " + r.intent);
1134 //Slog.i(TAG, "URI is: " + uri);
1135 //Slog.i(TAG, "To intent: " + intent2);
1136
1137 if (r.packageName != null) {
1138 // If the activity being launched is the same as the one currently
1139 // at the top, then we need to check if it should only be launched
1140 // once.
1141 ActivityRecord top = targetStack.topRunningNonDelayedActivityLocked(notTop);
1142 if (top != null && r.resultTo == null) {
1143 if (top.realActivity.equals(r.realActivity) && top.userId == r.userId) {
1144 if (top.app != null && top.app.thread != null) {
1145 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
1146 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP
1147 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
1148 ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, top,
1149 top.task);
1150 // For paranoia, make sure we have correctly
1151 // resumed the top activity.
1152 if (doResume) {
1153 targetStack.resumeTopActivityLocked(null);
1154 }
1155 ActivityOptions.abort(options);
1156 if ((startFlags&ActivityManager.START_FLAG_ONLY_IF_NEEDED) != 0) {
1157 // We don't need to start a new activity, and
1158 // the client said not to do anything if that
1159 // is the case, so this is it!
1160 return ActivityManager.START_RETURN_INTENT_TO_CALLER;
1161 }
1162 top.deliverNewIntentLocked(callingUid, r.intent);
1163 return ActivityManager.START_DELIVERED_TO_TOP;
1164 }
1165 }
1166 }
1167 }
1168
1169 } else {
1170 if (r.resultTo != null) {
1171 r.resultTo.task.stack.sendActivityResultLocked(-1,
1172 r.resultTo, r.resultWho, r.requestCode,
1173 Activity.RESULT_CANCELED, null);
1174 }
1175 ActivityOptions.abort(options);
1176 return ActivityManager.START_CLASS_NOT_FOUND;
1177 }
1178
1179 boolean newTask = false;
1180 boolean keepCurTransition = false;
1181
1182 // Should this be considered a new task?
1183 if (r.resultTo == null && !addingToTask
1184 && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
1185 if (reuseTask == null) {
1186 stack.setTask(r, targetStack.createTaskRecord(getNextTaskId(), r.info, intent,
1187 true), null, true);
1188 if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r
1189 + " in new task " + r.task);
1190 } else {
1191 stack.setTask(r, reuseTask, reuseTask, true);
1192 }
1193 newTask = true;
1194 if (!movedHome) {
1195 stack.moveHomeToFrontFromLaunchLocked(launchFlags);
1196 }
1197
1198 } else if (sourceRecord != null) {
1199 if (!addingToTask &&
1200 (launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
1201 // In this case, we are adding the activity to an existing
1202 // task, but the caller has asked to clear that task if the
1203 // activity is already running.
1204 ActivityRecord top = sourceRecord.task.performClearTaskLocked(r, launchFlags);
1205 keepCurTransition = true;
1206 if (top != null) {
1207 ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
1208 top.deliverNewIntentLocked(callingUid, r.intent);
1209 // For paranoia, make sure we have correctly
1210 // resumed the top activity.
1211 if (doResume) {
1212 targetStack.resumeTopActivityLocked(null);
1213 }
1214 ActivityOptions.abort(options);
1215 return ActivityManager.START_DELIVERED_TO_TOP;
1216 }
1217 } else if (!addingToTask &&
1218 (launchFlags&Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {
1219 // In this case, we are launching an activity in our own task
1220 // that may already be running somewhere in the history, and
1221 // we want to shuffle it to the front of the stack if so.
1222 final ActivityRecord top =
1223 targetStack.findActivityInHistoryLocked(r, sourceRecord.task);
1224 if (top != null) {
1225 targetStack.moveActivityToFrontLocked(top);
1226 ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
1227 top.updateOptionsLocked(options);
1228 top.deliverNewIntentLocked(callingUid, r.intent);
1229 if (doResume) {
1230 targetStack.resumeTopActivityLocked(null);
1231 }
1232 return ActivityManager.START_DELIVERED_TO_TOP;
1233 }
1234 }
1235 // An existing activity is starting this new activity, so we want
1236 // to keep the new one in the same task as the one that is starting
1237 // it.
1238 stack.setTask(r, sourceRecord.task, sourceRecord.thumbHolder, false);
1239 if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r
1240 + " in existing task " + r.task);
1241
1242 } else {
1243 // This not being started from an existing activity, and not part
1244 // of a new task... just put it in the top task, though these days
1245 // this case should never happen.
1246 ActivityRecord prev = stack.topActivity();
1247 stack.setTask(r, prev != null
1248 ? prev.task
1249 : stack.createTaskRecord(getNextTaskId(), r.info, intent, true), null, true);
1250 if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r
1251 + " in new guessed " + r.task);
1252 }
1253
1254 mService.grantUriPermissionFromIntentLocked(callingUid, r.packageName,
1255 intent, r.getUriPermissionsLocked());
1256
1257 if (newTask) {
1258 EventLog.writeEvent(EventLogTags.AM_CREATE_TASK, r.userId, r.task.taskId);
1259 }
1260 ActivityStack.logStartActivity(EventLogTags.AM_CREATE_ACTIVITY, r, r.task);
1261 targetStack.startActivityLocked(r, newTask, doResume, keepCurTransition, options);
1262 return ActivityManager.START_SUCCESS;
1263 }
1264
Craig Mautner8d341ef2013-03-26 09:03:27 -07001265 void handleAppDiedLocked(ProcessRecord app, boolean restarting) {
1266 // Just in case.
1267 final int numStacks = mStacks.size();
1268 for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
Craig Mautnere79d42682013-04-01 19:01:53 -07001269 mStacks.get(stackNdx).handleAppDiedLocked(app, restarting);
Craig Mautner8d341ef2013-03-26 09:03:27 -07001270 }
1271 }
1272
1273 void closeSystemDialogsLocked() {
1274 final int numStacks = mStacks.size();
1275 for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
1276 final ActivityStack stack = mStacks.get(stackNdx);
1277 stack.closeSystemDialogsLocked();
1278 }
1279 }
1280
1281 /**
1282 * @return true if some activity was finished (or would have finished if doit were true).
1283 */
1284 boolean forceStopPackageLocked(String name, boolean doit, boolean evenPersistent, int userId) {
1285 boolean didSomething = false;
1286 final int numStacks = mStacks.size();
1287 for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
1288 final ActivityStack stack = mStacks.get(stackNdx);
1289 if (stack.forceStopPackageLocked(name, doit, evenPersistent, userId)) {
1290 didSomething = true;
1291 }
1292 }
1293 return didSomething;
1294 }
1295
1296 void resumeTopActivityLocked() {
Craig Mautnerdbcb31f2013-04-02 12:32:53 -07001297 for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
Craig Mautner8d341ef2013-03-26 09:03:27 -07001298 mStacks.get(stackNdx).resumeTopActivityLocked(null);
1299 }
1300 }
1301
1302 void finishTopRunningActivityLocked(ProcessRecord app) {
1303 final int numStacks = mStacks.size();
1304 for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
1305 final ActivityStack stack = mStacks.get(stackNdx);
1306 stack.finishTopRunningActivityLocked(app);
1307 }
1308 }
1309
1310 void scheduleIdleLocked() {
1311 for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
1312 mStacks.get(stackNdx).scheduleIdleLocked();
1313 }
1314 }
1315
1316 void findTaskToMoveToFrontLocked(int taskId, int flags, Bundle options) {
1317 for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
1318 if (mStacks.get(stackNdx).findTaskToMoveToFrontLocked(taskId, flags, options)) {
1319 return;
1320 }
1321 }
1322 }
1323
1324 private ActivityStack getStack(int stackId) {
1325 for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
1326 final ActivityStack stack = mStacks.get(stackNdx);
1327 if (stack.getStackId() == stackId) {
1328 return stack;
1329 }
1330 }
1331 return null;
1332 }
1333
1334 int createStack(int relativeStackId, int position, float weight) {
1335 synchronized (this) {
1336 while (true) {
1337 if (++mLastStackId <= HOME_STACK_ID) {
1338 mLastStackId = HOME_STACK_ID + 1;
1339 }
1340 if (getStack(mLastStackId) == null) {
1341 break;
1342 }
1343 }
Craig Mautner2420ead2013-04-01 17:13:20 -07001344 mStacks.add(new ActivityStack(mService, mContext, mLooper, mLastStackId, this,
1345 mCurrentUser));
Craig Mautner8d341ef2013-03-26 09:03:27 -07001346 return mLastStackId;
1347 }
1348 }
1349
1350 void moveTaskToStack(int taskId, int stackId, boolean toTop) {
1351 final ActivityStack stack = getStack(stackId);
1352 if (stack == null) {
1353 Slog.w(TAG, "moveTaskToStack: no stack for id=" + stackId);
1354 return;
1355 }
1356 stack.moveTask(taskId, toTop);
1357 }
1358
Craig Mautner8849a5e2013-04-02 16:41:03 -07001359 ActivityRecord findTaskLocked(Intent intent, ActivityInfo info) {
1360 for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
1361 final ActivityRecord ar = mStacks.get(stackNdx).findTaskLocked(intent, info);
1362 if (ar != null) {
1363 return ar;
1364 }
1365 }
1366 return null;
1367 }
1368
1369 ActivityRecord findActivityLocked(Intent intent, ActivityInfo info) {
1370 for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
1371 final ActivityRecord ar = mStacks.get(stackNdx).findActivityLocked(intent, info);
1372 if (ar != null) {
1373 return ar;
1374 }
1375 }
1376 return null;
1377 }
1378
Craig Mautner8d341ef2013-03-26 09:03:27 -07001379 void goingToSleepLocked() {
1380 for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
1381 mStacks.get(stackNdx).stopIfSleepingLocked();
1382 }
1383 }
1384
1385 boolean shutdownLocked(int timeout) {
1386 boolean timedout = false;
1387 final int numStacks = mStacks.size();
1388 for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
1389 final ActivityStack stack = mStacks.get(stackNdx);
1390 if (stack.mResumedActivity != null) {
1391 stack.stopIfSleepingLocked();
1392 final long endTime = System.currentTimeMillis() + timeout;
1393 while (stack.mResumedActivity != null || stack.mPausingActivity != null) {
1394 long delay = endTime - System.currentTimeMillis();
1395 if (delay <= 0) {
1396 Slog.w(TAG, "Activity manager shutdown timed out");
1397 timedout = true;
1398 break;
1399 }
1400 try {
1401 mService.wait();
1402 } catch (InterruptedException e) {
1403 }
1404 }
1405 }
1406 }
1407 return timedout;
1408 }
1409
1410 void comeOutOfSleepIfNeededLocked() {
1411 final int numStacks = mStacks.size();
1412 for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
1413 final ActivityStack stack = mStacks.get(stackNdx);
1414 stack.awakeFromSleepingLocked();
1415 stack.resumeTopActivityLocked(null);
1416 }
1417 }
1418
1419 void handleAppCrashLocked(ProcessRecord app) {
1420 final int numStacks = mStacks.size();
1421 for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
1422 final ActivityStack stack = mStacks.get(stackNdx);
1423 stack.handleAppCrashLocked(app);
1424 }
1425 }
1426
1427 boolean updateConfigurationLocked(int changes, ActivityRecord starting) {
1428 boolean kept = true;
1429 final int numStacks = mStacks.size();
1430 for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
1431 final ActivityStack stack = mStacks.get(stackNdx);
1432 if (changes != 0 && starting == null) {
1433 // If the configuration changed, and the caller is not already
1434 // in the process of starting an activity, then find the top
1435 // activity to check if its configuration needs to change.
1436 starting = stack.topRunningActivityLocked(null);
1437 }
1438
1439 if (starting != null) {
1440 if (!stack.ensureActivityConfigurationLocked(starting, changes)) {
1441 kept = false;
1442 }
1443 // And we need to make sure at this point that all other activities
1444 // are made visible with the correct configuration.
1445 stack.ensureActivitiesVisibleLocked(starting, changes);
1446 }
1447 }
1448 return kept;
1449 }
1450
1451 void scheduleDestroyAllActivities(ProcessRecord app, String reason) {
1452 final int numStacks = mStacks.size();
1453 for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
1454 final ActivityStack stack = mStacks.get(stackNdx);
1455 stack.scheduleDestroyActivities(app, false, reason);
1456 }
1457 }
1458
1459 boolean switchUserLocked(int userId, UserStartedState uss) {
Craig Mautner2420ead2013-04-01 17:13:20 -07001460 mCurrentUser = userId;
Craig Mautner8d341ef2013-03-26 09:03:27 -07001461 boolean haveActivities = false;
1462 final int numStacks = mStacks.size();
1463 for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
1464 final ActivityStack stack = mStacks.get(stackNdx);
1465 haveActivities |= stack.switchUserLocked(userId, uss);
1466 }
1467 return haveActivities;
Craig Mautner2219a1b2013-03-25 09:44:30 -07001468 }
1469
Craig Mautner27084302013-03-25 08:05:25 -07001470 public void dump(PrintWriter pw, String prefix) {
1471 pw.print(prefix); pw.print("mDismissKeyguardOnNextActivity:");
1472 pw.println(mDismissKeyguardOnNextActivity);
1473 }
Craig Mautner8d341ef2013-03-26 09:03:27 -07001474
Craig Mautner20e72272013-04-01 13:45:53 -07001475 ArrayList<ActivityRecord> getDumpActivitiesLocked(String name) {
1476 return mMainStack.getDumpActivitiesLocked(name);
1477 }
1478
Craig Mautner8d341ef2013-03-26 09:03:27 -07001479 boolean dumpActivitiesLocked(FileDescriptor fd, PrintWriter pw, boolean dumpAll,
1480 boolean dumpClient, String dumpPackage) {
1481 final int numStacks = mStacks.size();
1482 for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
1483 final ActivityStack stack = mStacks.get(stackNdx);
1484 pw.print(" Stack #"); pw.print(mStacks.indexOf(stack)); pw.println(":");
1485 stack.dumpActivitiesLocked(fd, pw, dumpAll, dumpClient, dumpPackage);
1486 pw.println(" ");
1487 pw.println(" Running activities (most recent first):");
1488 dumpHistoryList(fd, pw, stack.mLRUActivities, " ", "Run", false, !dumpAll, false,
1489 dumpPackage);
1490 if (stack.mWaitingVisibleActivities.size() > 0) {
1491 pw.println(" ");
1492 pw.println(" Activities waiting for another to become visible:");
1493 dumpHistoryList(fd, pw, stack.mWaitingVisibleActivities, " ", "Wait", false,
1494 !dumpAll, false, dumpPackage);
1495 }
1496 if (stack.mStoppingActivities.size() > 0) {
1497 pw.println(" ");
1498 pw.println(" Activities waiting to stop:");
1499 dumpHistoryList(fd, pw, stack.mStoppingActivities, " ", "Stop", false,
1500 !dumpAll, false, dumpPackage);
1501 }
1502 if (stack.mGoingToSleepActivities.size() > 0) {
1503 pw.println(" ");
1504 pw.println(" Activities waiting to sleep:");
1505 dumpHistoryList(fd, pw, stack.mGoingToSleepActivities, " ", "Sleep", false,
1506 !dumpAll, false, dumpPackage);
1507 }
1508 if (stack.mFinishingActivities.size() > 0) {
1509 pw.println(" ");
1510 pw.println(" Activities waiting to finish:");
1511 dumpHistoryList(fd, pw, stack.mFinishingActivities, " ", "Fin", false,
1512 !dumpAll, false, dumpPackage);
1513 }
1514 }
1515
1516 for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
1517 final ActivityStack stack = mStacks.get(stackNdx);
1518 pw.print(" Stack #"); pw.println(mStacks.indexOf(stack));
1519 if (stack.mPausingActivity != null) {
1520 pw.println(" mPausingActivity: " + stack.mPausingActivity);
1521 }
1522 pw.println(" mResumedActivity: " + stack.mResumedActivity);
1523 if (dumpAll) {
1524 pw.println(" mLastPausedActivity: " + stack.mLastPausedActivity);
1525 pw.println(" mSleepTimeout: " + stack.mSleepTimeout);
1526 }
1527 }
1528
1529 if (dumpAll) {
1530 pw.println(" ");
1531 pw.println(" mCurTaskId: " + mCurTaskId);
1532 }
1533 return true;
1534 }
1535
1536 static final void dumpHistoryList(FileDescriptor fd, PrintWriter pw, List<ActivityRecord> list,
1537 String prefix, String label, boolean complete, boolean brief, boolean client,
1538 String dumpPackage) {
1539 TaskRecord lastTask = null;
1540 boolean needNL = false;
1541 final String innerPrefix = prefix + " ";
1542 final String[] args = new String[0];
1543 for (int i=list.size()-1; i>=0; i--) {
1544 final ActivityRecord r = list.get(i);
1545 if (dumpPackage != null && !dumpPackage.equals(r.packageName)) {
1546 continue;
1547 }
1548 final boolean full = !brief && (complete || !r.isInHistory());
1549 if (needNL) {
1550 pw.println(" ");
1551 needNL = false;
1552 }
1553 if (lastTask != r.task) {
1554 lastTask = r.task;
1555 pw.print(prefix);
1556 pw.print(full ? "* " : " ");
1557 pw.println(lastTask);
1558 if (full) {
1559 lastTask.dump(pw, prefix + " ");
1560 } else if (complete) {
1561 // Complete + brief == give a summary. Isn't that obvious?!?
1562 if (lastTask.intent != null) {
1563 pw.print(prefix); pw.print(" ");
1564 pw.println(lastTask.intent.toInsecureStringWithClip());
1565 }
1566 }
1567 }
1568 pw.print(prefix); pw.print(full ? " * " : " "); pw.print(label);
1569 pw.print(" #"); pw.print(i); pw.print(": ");
1570 pw.println(r);
1571 if (full) {
1572 r.dump(pw, innerPrefix);
1573 } else if (complete) {
1574 // Complete + brief == give a summary. Isn't that obvious?!?
1575 pw.print(innerPrefix); pw.println(r.intent.toInsecureString());
1576 if (r.app != null) {
1577 pw.print(innerPrefix); pw.println(r.app);
1578 }
1579 }
1580 if (client && r.app != null && r.app.thread != null) {
1581 // flush anything that is already in the PrintWriter since the thread is going
1582 // to write to the file descriptor directly
1583 pw.flush();
1584 try {
1585 TransferPipe tp = new TransferPipe();
1586 try {
1587 r.app.thread.dumpActivity(tp.getWriteFd().getFileDescriptor(),
1588 r.appToken, innerPrefix, args);
1589 // Short timeout, since blocking here can
1590 // deadlock with the application.
1591 tp.go(fd, 2000);
1592 } finally {
1593 tp.kill();
1594 }
1595 } catch (IOException e) {
1596 pw.println(innerPrefix + "Failure while dumping the activity: " + e);
1597 } catch (RemoteException e) {
1598 pw.println(innerPrefix + "Got a RemoteException while dumping the activity");
1599 }
1600 needNL = true;
1601 }
1602 }
1603 }
Craig Mautner27084302013-03-25 08:05:25 -07001604}