blob: ae16b1433ae790dd4457d87d640e60292ada5fc2 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
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 com.android.server.am;
18
19import com.android.server.AttributeCache;
20import com.android.server.am.ActivityManagerService.ActivityState;
21
22import android.app.Activity;
23import android.content.ComponentName;
24import android.content.Intent;
25import android.content.pm.ActivityInfo;
26import android.content.pm.ApplicationInfo;
27import android.content.res.Configuration;
28import android.graphics.Bitmap;
29import android.os.Bundle;
30import android.os.Message;
31import android.os.Process;
32import android.os.SystemClock;
33import android.util.EventLog;
34import android.util.Log;
35import android.view.IApplicationToken;
36
37import java.io.PrintWriter;
38import java.lang.ref.WeakReference;
39import java.util.ArrayList;
40import java.util.HashSet;
41
42/**
43 * An entry in the history stack, representing an activity.
44 */
45class HistoryRecord extends IApplicationToken.Stub {
46 final ActivityManagerService service; // owner
47 final ActivityInfo info; // all about me
48 final int launchedFromUid; // always the uid who started the activity.
49 final Intent intent; // the original intent that generated us
50 final ComponentName realActivity; // the intent component, or target of an alias.
51 final String shortComponentName; // the short component name of the intent
52 final String resolvedType; // as per original caller;
53 final String packageName; // the package implementing intent's component
54 final String processName; // process where this component wants to run
55 final String taskAffinity; // as per ActivityInfo.taskAffinity
56 final boolean stateNotNeeded; // As per ActivityInfo.flags
57 final boolean fullscreen; // covers the full screen?
The Android Open Source Project4df24232009-03-05 14:34:35 -080058 final boolean componentSpecified; // did caller specifiy an explicit component?
59 final boolean isHomeActivity; // do we consider this to be a home activity?
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080060 final String baseDir; // where activity source (resources etc) located
61 final String resDir; // where public activity source (public resources etc) located
62 final String dataDir; // where activity data should go
63 CharSequence nonLocalizedLabel; // the label information from the package mgr.
64 int labelRes; // the label information from the package mgr.
65 int icon; // resource identifier of activity's icon.
66 int theme; // resource identifier of activity's theme.
67 TaskRecord task; // the task this is in.
68 long startTime; // when we starting launching this activity
69 Configuration configuration; // configuration activity was last running in
70 HistoryRecord resultTo; // who started this entry, so will get our reply
71 final String resultWho; // additional identifier for use by resultTo.
72 final int requestCode; // code given by requester (resultTo)
73 ArrayList results; // pending ActivityResult objs we have received
74 HashSet<WeakReference<PendingIntentRecord>> pendingResults; // all pending intents for this act
75 ArrayList newIntents; // any pending new intents for single-top mode
76 HashSet<ConnectionRecord> connections; // All ConnectionRecord we hold
77 HashSet<UriPermission> readUriPermissions; // special access to reading uris.
78 HashSet<UriPermission> writeUriPermissions; // special access to writing uris.
79 ProcessRecord app; // if non-null, hosting application
80 Bitmap thumbnail; // icon representation of paused screen
81 CharSequence description; // textual description of paused screen
82 ActivityManagerService.ActivityState state; // current state we are in
83 Bundle icicle; // last saved activity state
84 boolean frontOfTask; // is this the root activity of its task?
85 boolean launchFailed; // set if a launched failed, to abort on 2nd try
86 boolean haveState; // have we gotten the last activity state?
87 boolean stopped; // is activity pause finished?
88 boolean finishing; // activity in pending finish list?
89 boolean configDestroy; // need to destroy due to config change?
90 int configChangeFlags; // which config values have changed
91 boolean keysPaused; // has key dispatching been paused for it?
92 boolean inHistory; // are we in the history stack?
93 boolean persistent; // requested to be persistent?
94 int launchMode; // the launch mode activity attribute.
95 boolean visible; // does this activity's window need to be shown?
96 boolean waitingVisible; // true if waiting for a new act to become vis
97 boolean nowVisible; // is this activity's window visible?
98 boolean thumbnailNeeded;// has someone requested a thumbnail?
99 boolean idle; // has the activity gone idle?
100 boolean hasBeenLaunched;// has this activity ever been launched?
101 boolean frozenBeforeDestroy;// has been frozen but not yet destroyed.
102
103 void dump(PrintWriter pw, String prefix) {
104 pw.println(prefix + this);
105 pw.println(prefix + "packageName=" + packageName
106 + " processName=" + processName);
The Android Open Source Project4df24232009-03-05 14:34:35 -0800107 pw.println(prefix + "launchedFromUid=" + launchedFromUid
108 + " app=" + app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800109 pw.println(prefix + intent);
110 pw.println(prefix + "frontOfTask=" + frontOfTask + " task=" + task);
111 pw.println(prefix + "taskAffinity=" + taskAffinity);
112 pw.println(prefix + "realActivity=" + realActivity);
113 pw.println(prefix + "dir=" + baseDir + " res=" + resDir + " data=" + dataDir);
114 pw.println(prefix + "labelRes=0x" + Integer.toHexString(labelRes)
115 + " icon=0x" + Integer.toHexString(icon)
116 + " theme=0x" + Integer.toHexString(theme));
The Android Open Source Project4df24232009-03-05 14:34:35 -0800117 pw.println(prefix + "stateNotNeeded=" + stateNotNeeded
118 + " componentSpecified=" + componentSpecified
119 + " isHomeActivity=" + isHomeActivity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800120 pw.println(prefix + "configuration=" + configuration);
121 pw.println(prefix + "resultTo=" + resultTo
122 + " resultWho=" + resultWho + " resultCode=" + requestCode);
123 pw.println(prefix + "results=" + results);
124 pw.println(prefix + "pendingResults=" + pendingResults);
125 pw.println(prefix + "readUriPermissions=" + readUriPermissions);
126 pw.println(prefix + "writeUriPermissions=" + writeUriPermissions);
127 pw.println(prefix + "launchFailed=" + launchFailed
128 + " haveState=" + haveState + " icicle=" + icicle);
129 pw.println(prefix + "state=" + state
130 + " stopped=" + stopped + " finishing=" + finishing);
131 pw.println(prefix + "keysPaused=" + keysPaused
132 + " inHistory=" + inHistory + " persistent=" + persistent
133 + " launchMode=" + launchMode);
134 pw.println(prefix + "fullscreen=" + fullscreen
135 + " visible=" + visible
136 + " frozenBeforeDestroy=" + frozenBeforeDestroy
137 + " thumbnailNeeded=" + thumbnailNeeded + " idle=" + idle);
138 pw.println(prefix + "waitingVisible=" + waitingVisible
139 + " nowVisible=" + nowVisible);
140 pw.println(prefix + "configDestroy=" + configDestroy
141 + " configChangeFlags=" + Integer.toHexString(configChangeFlags));
142 pw.println(prefix + "connections=" + connections);
143 }
144
145 HistoryRecord(ActivityManagerService _service, ProcessRecord _caller,
146 int _launchedFromUid, Intent _intent, String _resolvedType,
147 ActivityInfo aInfo, Configuration _configuration,
The Android Open Source Project4df24232009-03-05 14:34:35 -0800148 HistoryRecord _resultTo, String _resultWho, int _reqCode,
149 boolean _componentSpecified) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800150 service = _service;
151 info = aInfo;
152 launchedFromUid = _launchedFromUid;
153 intent = _intent;
154 shortComponentName = _intent.getComponent().flattenToShortString();
155 resolvedType = _resolvedType;
The Android Open Source Project4df24232009-03-05 14:34:35 -0800156 componentSpecified = _componentSpecified;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800157 configuration = _configuration;
158 resultTo = _resultTo;
159 resultWho = _resultWho;
160 requestCode = _reqCode;
161 state = ActivityManagerService.ActivityState.INITIALIZING;
162 frontOfTask = false;
163 launchFailed = false;
164 haveState = false;
165 stopped = false;
166 finishing = false;
167 configDestroy = false;
168 keysPaused = false;
169 inHistory = false;
170 persistent = false;
171 visible = true;
172 waitingVisible = false;
173 nowVisible = false;
174 thumbnailNeeded = false;
175 idle = false;
176 hasBeenLaunched = false;
177
178 if (aInfo != null) {
179 if (aInfo.targetActivity == null
180 || aInfo.launchMode == ActivityInfo.LAUNCH_MULTIPLE
181 || aInfo.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP) {
182 realActivity = _intent.getComponent();
183 } else {
184 realActivity = new ComponentName(aInfo.packageName,
185 aInfo.targetActivity);
186 }
187 taskAffinity = aInfo.taskAffinity;
188 stateNotNeeded = (aInfo.flags&
189 ActivityInfo.FLAG_STATE_NOT_NEEDED) != 0;
190 baseDir = aInfo.applicationInfo.sourceDir;
191 resDir = aInfo.applicationInfo.publicSourceDir;
192 dataDir = aInfo.applicationInfo.dataDir;
193 nonLocalizedLabel = aInfo.nonLocalizedLabel;
194 labelRes = aInfo.labelRes;
195 if (nonLocalizedLabel == null && labelRes == 0) {
196 ApplicationInfo app = aInfo.applicationInfo;
197 nonLocalizedLabel = app.nonLocalizedLabel;
198 labelRes = app.labelRes;
199 }
200 icon = aInfo.getIconResource();
201 theme = aInfo.getThemeResource();
202 if ((aInfo.flags&ActivityInfo.FLAG_MULTIPROCESS) != 0
203 && _caller != null
204 && (aInfo.applicationInfo.uid == Process.SYSTEM_UID
205 || aInfo.applicationInfo.uid == _caller.info.uid)) {
206 processName = _caller.processName;
207 } else {
208 processName = aInfo.processName;
209 }
210
211 if (intent != null && (aInfo.flags & ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS) != 0) {
212 intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
213 }
214
215 packageName = aInfo.applicationInfo.packageName;
216 launchMode = aInfo.launchMode;
217
218 AttributeCache.Entry ent = AttributeCache.instance().get(packageName,
219 theme != 0 ? theme : android.R.style.Theme,
220 com.android.internal.R.styleable.Window);
221 fullscreen = ent != null && !ent.array.getBoolean(
222 com.android.internal.R.styleable.Window_windowIsFloating, false)
223 && !ent.array.getBoolean(
224 com.android.internal.R.styleable.Window_windowIsTranslucent, false);
225
The Android Open Source Project4df24232009-03-05 14:34:35 -0800226 if (!_componentSpecified || _launchedFromUid == Process.myUid()
227 || _launchedFromUid == 0) {
228 // If we know the system has determined the component, then
229 // we can consider this to be a home activity...
230 if (Intent.ACTION_MAIN.equals(_intent.getAction()) &&
231 _intent.hasCategory(Intent.CATEGORY_HOME) &&
232 _intent.getCategories().size() == 1 &&
233 _intent.getData() == null &&
234 _intent.getType() == null &&
235 (intent.getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
236 !"android".equals(realActivity.getClassName())) {
237 // This sure looks like a home activity!
238 // Note the last check is so we don't count the resolver
239 // activity as being home... really, we don't care about
240 // doing anything special with something that comes from
241 // the core framework package.
242 isHomeActivity = true;
243 } else {
244 isHomeActivity = false;
245 }
246 } else {
247 isHomeActivity = false;
248 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800249 } else {
250 realActivity = null;
251 taskAffinity = null;
252 stateNotNeeded = false;
253 baseDir = null;
254 resDir = null;
255 dataDir = null;
256 processName = null;
257 packageName = null;
258 fullscreen = true;
The Android Open Source Project4df24232009-03-05 14:34:35 -0800259 isHomeActivity = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800260 }
261 }
262
263 void addResultLocked(HistoryRecord from, String resultWho,
264 int requestCode, int resultCode,
265 Intent resultData) {
266 ActivityResult r = new ActivityResult(from, resultWho,
267 requestCode, resultCode, resultData);
268 if (results == null) {
269 results = new ArrayList();
270 }
271 results.add(r);
272 }
273
274 void removeResultsLocked(HistoryRecord from, String resultWho,
275 int requestCode) {
276 if (results != null) {
277 for (int i=results.size()-1; i>=0; i--) {
278 ActivityResult r = (ActivityResult)results.get(i);
279 if (r.mFrom != from) continue;
280 if (r.mResultWho == null) {
281 if (resultWho != null) continue;
282 } else {
283 if (!r.mResultWho.equals(resultWho)) continue;
284 }
285 if (r.mRequestCode != requestCode) continue;
286
287 results.remove(i);
288 }
289 }
290 }
291
292 void addNewIntentLocked(Intent intent) {
293 if (newIntents == null) {
294 newIntents = new ArrayList();
295 }
296 newIntents.add(intent);
297 }
298
299 void pauseKeyDispatchingLocked() {
300 if (!keysPaused) {
301 keysPaused = true;
302 service.mWindowManager.pauseKeyDispatching(this);
303 }
304 }
305
306 void resumeKeyDispatchingLocked() {
307 if (keysPaused) {
308 keysPaused = false;
309 service.mWindowManager.resumeKeyDispatching(this);
310 }
311 }
312
313 // IApplicationToken
314
315 public boolean mayFreezeScreenLocked(ProcessRecord app) {
316 // Only freeze the screen if this activity is currently attached to
317 // an application, and that application is not blocked or unresponding.
318 // In any other case, we can't count on getting the screen unfrozen,
319 // so it is best to leave as-is.
320 return app == null || (!app.crashing && !app.notResponding);
321 }
322
323 public void startFreezingScreenLocked(ProcessRecord app, int configChanges) {
324 if (mayFreezeScreenLocked(app)) {
325 service.mWindowManager.startAppFreezingScreen(this, configChanges);
326 }
327 }
328
329 public void stopFreezingScreenLocked(boolean force) {
330 if (force || frozenBeforeDestroy) {
331 frozenBeforeDestroy = false;
332 service.mWindowManager.stopAppFreezingScreen(this, force);
333 }
334 }
335
336 public void windowsVisible() {
337 synchronized(service) {
Dianne Hackborn6447ca32009-04-07 19:50:08 -0700338 if (startTime != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800339 long time = SystemClock.uptimeMillis() - startTime;
Dianne Hackborn6447ca32009-04-07 19:50:08 -0700340 if (ActivityManagerService.SHOW_ACTIVITY_START_TIME) {
341 EventLog.writeEvent(ActivityManagerService.LOG_ACTIVITY_LAUNCH_TIME,
342 System.identityHashCode(this), shortComponentName, time);
343 Log.i(ActivityManagerService.TAG, "Displayed activity "
344 + shortComponentName
345 + ": " + time + " ms");
346 }
347 if (time > 0) {
348 service.mUsageStatsService.noteLaunchTime(realActivity, (int)time);
349 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800350 startTime = 0;
351 }
352 if (ActivityManagerService.DEBUG_SWITCH) Log.v(
353 ActivityManagerService.TAG, "windowsVisible(): " + this);
354 if (!nowVisible) {
355 nowVisible = true;
356 if (!idle) {
357 // Instead of doing the full stop routine here, let's just
358 // hide any activities we now can, and let them stop when
359 // the normal idle happens.
360 service.processStoppingActivitiesLocked(false);
361 } else {
362 // If this activity was already idle, then we now need to
363 // make sure we perform the full stop of any activities
364 // that are waiting to do so. This is because we won't
365 // do that while they are still waiting for this one to
366 // become visible.
367 final int N = service.mWaitingVisibleActivities.size();
368 if (N > 0) {
369 for (int i=0; i<N; i++) {
370 HistoryRecord r = (HistoryRecord)
371 service.mWaitingVisibleActivities.get(i);
372 r.waitingVisible = false;
373 if (ActivityManagerService.DEBUG_SWITCH) Log.v(
374 ActivityManagerService.TAG,
375 "Was waiting for visible: " + r);
376 }
377 service.mWaitingVisibleActivities.clear();
378 Message msg = Message.obtain();
379 msg.what = ActivityManagerService.IDLE_NOW_MSG;
380 service.mHandler.sendMessage(msg);
381 }
382 }
383 service.scheduleAppGcsLocked();
384 }
385 }
386 }
387
388 public void windowsGone() {
389 if (ActivityManagerService.DEBUG_SWITCH) Log.v(
390 ActivityManagerService.TAG, "windowsGone(): " + this);
391 nowVisible = false;
392 }
393
394 private HistoryRecord getWaitingHistoryRecordLocked() {
395 // First find the real culprit... if we are waiting
396 // for another app to start, then we have paused dispatching
397 // for this activity.
398 HistoryRecord r = this;
399 if (r.waitingVisible) {
400 // Hmmm, who might we be waiting for?
401 r = service.mResumedActivity;
402 if (r == null) {
403 r = service.mPausingActivity;
404 }
405 // Both of those null? Fall back to 'this' again
406 if (r == null) {
407 r = this;
408 }
409 }
410
411 return r;
412 }
413
414 public boolean keyDispatchingTimedOut() {
415 synchronized(service) {
416 HistoryRecord r = getWaitingHistoryRecordLocked();
417 if (r != null && r.app != null) {
418 if (r.app.debugging) {
419 return false;
420 }
421
422 if (r.app.instrumentationClass == null) {
423 service.appNotRespondingLocked(r.app, r, "keyDispatchingTimedOut");
424 } else {
425 Bundle info = new Bundle();
426 info.putString("shortMsg", "keyDispatchingTimedOut");
427 info.putString("longMsg", "Timed out while dispatching key event");
428 service.finishInstrumentationLocked(
429 r.app, Activity.RESULT_CANCELED, info);
430 }
431 }
432 return true;
433 }
434 }
435
436 /** Returns the key dispatching timeout for this application token. */
437 public long getKeyDispatchingTimeout() {
438 synchronized(service) {
439 HistoryRecord r = getWaitingHistoryRecordLocked();
440 if (r == null || r.app == null
441 || r.app.instrumentationClass == null) {
442 return ActivityManagerService.KEY_DISPATCHING_TIMEOUT;
443 }
444
445 return ActivityManagerService.INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT;
446 }
447 }
448
449 /**
450 * This method will return true if the activity is either visible, is becoming visible, is
451 * currently pausing, or is resumed.
452 */
453 public boolean isInterestingToUserLocked() {
454 return visible || nowVisible || state == ActivityState.PAUSING ||
455 state == ActivityState.RESUMED;
456 }
457
458
459 public String toString() {
460 return "HistoryRecord{"
461 + Integer.toHexString(System.identityHashCode(this))
462 + " " + intent.getComponent().toShortString() + "}";
463 }
464}