1/*
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?
58    final boolean componentSpecified;  // did caller specifiy an explicit component?
59    final boolean isHomeActivity; // do we consider this to be a home activity?
60    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    long cpuTimeAtResume;   // the cpu time of host process at the time of resuming activity
70    Configuration configuration; // configuration activity was last running in
71    HistoryRecord resultTo; // who started this entry, so will get our reply
72    final String resultWho; // additional identifier for use by resultTo.
73    final int requestCode;  // code given by requester (resultTo)
74    ArrayList results;      // pending ActivityResult objs we have received
75    HashSet<WeakReference<PendingIntentRecord>> pendingResults; // all pending intents for this act
76    ArrayList newIntents;   // any pending new intents for single-top mode
77    HashSet<ConnectionRecord> connections; // All ConnectionRecord we hold
78    HashSet<UriPermission> readUriPermissions; // special access to reading uris.
79    HashSet<UriPermission> writeUriPermissions; // special access to writing uris.
80    ProcessRecord app;  // if non-null, hosting application
81    Bitmap thumbnail;       // icon representation of paused screen
82    CharSequence description; // textual description of paused screen
83    ActivityManagerService.ActivityState state;    // current state we are in
84    Bundle  icicle;         // last saved activity state
85    boolean frontOfTask;    // is this the root activity of its task?
86    boolean launchFailed;   // set if a launched failed, to abort on 2nd try
87    boolean haveState;      // have we gotten the last activity state?
88    boolean stopped;        // is activity pause finished?
89    boolean delayedResume;  // not yet resumed because of stopped app switches?
90    boolean finishing;      // activity in pending finish list?
91    boolean configDestroy;  // need to destroy due to config change?
92    int configChangeFlags;  // which config values have changed
93    boolean keysPaused;     // has key dispatching been paused for it?
94    boolean inHistory;      // are we in the history stack?
95    boolean persistent;     // requested to be persistent?
96    int launchMode;         // the launch mode activity attribute.
97    boolean visible;        // does this activity's window need to be shown?
98    boolean waitingVisible; // true if waiting for a new act to become vis
99    boolean nowVisible;     // is this activity's window visible?
100    boolean thumbnailNeeded;// has someone requested a thumbnail?
101    boolean idle;           // has the activity gone idle?
102    boolean hasBeenLaunched;// has this activity ever been launched?
103    boolean frozenBeforeDestroy;// has been frozen but not yet destroyed.
104
105    String stringName;      // for caching of toString().
106
107    void dump(PrintWriter pw, String prefix) {
108        pw.print(prefix); pw.print("packageName="); pw.print(packageName);
109                pw.print(" processName="); pw.println(processName);
110        pw.print(prefix); pw.print("launchedFromUid="); pw.print(launchedFromUid);
111                pw.print(" app="); pw.println(app);
112        pw.print(prefix); pw.println(intent);
113        pw.print(prefix); pw.print("frontOfTask="); pw.print(frontOfTask);
114                pw.print(" task="); pw.println(task);
115        pw.print(prefix); pw.print("taskAffinity="); pw.println(taskAffinity);
116        pw.print(prefix); pw.print("realActivity=");
117                pw.println(realActivity.flattenToShortString());
118        pw.print(prefix); pw.print("base="); pw.print(baseDir);
119                if (!resDir.equals(baseDir)) pw.print(" res="); pw.print(resDir);
120                pw.print(" data="); pw.println(dataDir);
121        pw.print(prefix); pw.print("labelRes=0x");
122                pw.print(Integer.toHexString(labelRes));
123                pw.print(" icon=0x"); pw.print(Integer.toHexString(icon));
124                pw.print(" theme=0x"); pw.println(Integer.toHexString(theme));
125        pw.print(prefix); pw.print("stateNotNeeded="); pw.print(stateNotNeeded);
126                pw.print(" componentSpecified="); pw.print(componentSpecified);
127                pw.print(" isHomeActivity="); pw.println(isHomeActivity);
128        pw.print(prefix); pw.print("configuration="); pw.println(configuration);
129        if (resultTo != null || resultWho != null) {
130            pw.print(prefix); pw.print("resultTo="); pw.print(resultTo);
131                    pw.print(" resultWho="); pw.print(resultWho);
132                    pw.print(" resultCode="); pw.println(requestCode);
133        }
134        if (results != null) {
135            pw.print(prefix); pw.print("results="); pw.println(results);
136        }
137        if (pendingResults != null) {
138            pw.print(prefix); pw.print("pendingResults="); pw.println(pendingResults);
139        }
140        if (readUriPermissions != null) {
141            pw.print(prefix); pw.print("readUriPermissions="); pw.println(readUriPermissions);
142        }
143        if (writeUriPermissions != null) {
144            pw.print(prefix); pw.print("writeUriPermissions="); pw.println(writeUriPermissions);
145        }
146        pw.print(prefix); pw.print("launchFailed="); pw.print(launchFailed);
147                pw.print(" haveState="); pw.print(haveState);
148                pw.print(" icicle="); pw.println(icicle);
149        pw.print(prefix); pw.print("state="); pw.print(state);
150                pw.print(" stopped="); pw.print(stopped);
151                pw.print(" delayedResume="); pw.print(delayedResume);
152                pw.print(" finishing="); pw.println(finishing);
153        pw.print(prefix); pw.print("keysPaused="); pw.print(keysPaused);
154                pw.print(" inHistory="); pw.print(inHistory);
155                pw.print(" persistent="); pw.print(persistent);
156                pw.print(" launchMode="); pw.println(launchMode);
157        pw.print(prefix); pw.print("fullscreen="); pw.print(fullscreen);
158                pw.print(" visible="); pw.print(visible);
159                pw.print(" frozenBeforeDestroy="); pw.print(frozenBeforeDestroy);
160                pw.print(" thumbnailNeeded="); pw.print(thumbnailNeeded);
161                pw.print(" idle="); pw.println(idle);
162        if (waitingVisible || nowVisible) {
163            pw.print(prefix); pw.print("waitingVisible="); pw.print(waitingVisible);
164                    pw.print(" nowVisible="); pw.println(nowVisible);
165        }
166        if (configDestroy || configChangeFlags != 0) {
167            pw.print(prefix); pw.print("configDestroy="); pw.print(configDestroy);
168                    pw.print(" configChangeFlags=");
169                    pw.println(Integer.toHexString(configChangeFlags));
170        }
171        if (connections != null) {
172            pw.print(prefix); pw.print("connections="); pw.println(connections);
173        }
174    }
175
176    HistoryRecord(ActivityManagerService _service, ProcessRecord _caller,
177            int _launchedFromUid, Intent _intent, String _resolvedType,
178            ActivityInfo aInfo, Configuration _configuration,
179            HistoryRecord _resultTo, String _resultWho, int _reqCode,
180            boolean _componentSpecified) {
181        service = _service;
182        info = aInfo;
183        launchedFromUid = _launchedFromUid;
184        intent = _intent;
185        shortComponentName = _intent.getComponent().flattenToShortString();
186        resolvedType = _resolvedType;
187        componentSpecified = _componentSpecified;
188        configuration = _configuration;
189        resultTo = _resultTo;
190        resultWho = _resultWho;
191        requestCode = _reqCode;
192        state = ActivityManagerService.ActivityState.INITIALIZING;
193        frontOfTask = false;
194        launchFailed = false;
195        haveState = false;
196        stopped = false;
197        delayedResume = false;
198        finishing = false;
199        configDestroy = false;
200        keysPaused = false;
201        inHistory = false;
202        persistent = false;
203        visible = true;
204        waitingVisible = false;
205        nowVisible = false;
206        thumbnailNeeded = false;
207        idle = false;
208        hasBeenLaunched = false;
209
210        if (aInfo != null) {
211            if (aInfo.targetActivity == null
212                    || aInfo.launchMode == ActivityInfo.LAUNCH_MULTIPLE
213                    || aInfo.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP) {
214                realActivity = _intent.getComponent();
215            } else {
216                realActivity = new ComponentName(aInfo.packageName,
217                        aInfo.targetActivity);
218            }
219            taskAffinity = aInfo.taskAffinity;
220            stateNotNeeded = (aInfo.flags&
221                    ActivityInfo.FLAG_STATE_NOT_NEEDED) != 0;
222            baseDir = aInfo.applicationInfo.sourceDir;
223            resDir = aInfo.applicationInfo.publicSourceDir;
224            dataDir = aInfo.applicationInfo.dataDir;
225            nonLocalizedLabel = aInfo.nonLocalizedLabel;
226            labelRes = aInfo.labelRes;
227            if (nonLocalizedLabel == null && labelRes == 0) {
228                ApplicationInfo app = aInfo.applicationInfo;
229                nonLocalizedLabel = app.nonLocalizedLabel;
230                labelRes = app.labelRes;
231            }
232            icon = aInfo.getIconResource();
233            theme = aInfo.getThemeResource();
234            if ((aInfo.flags&ActivityInfo.FLAG_MULTIPROCESS) != 0
235                    && _caller != null
236                    && (aInfo.applicationInfo.uid == Process.SYSTEM_UID
237                            || aInfo.applicationInfo.uid == _caller.info.uid)) {
238                processName = _caller.processName;
239            } else {
240                processName = aInfo.processName;
241            }
242
243            if (intent != null && (aInfo.flags & ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS) != 0) {
244                intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
245            }
246
247            packageName = aInfo.applicationInfo.packageName;
248            launchMode = aInfo.launchMode;
249
250            AttributeCache.Entry ent = AttributeCache.instance().get(packageName,
251                    theme != 0 ? theme : android.R.style.Theme,
252                    com.android.internal.R.styleable.Window);
253            fullscreen = ent != null && !ent.array.getBoolean(
254                    com.android.internal.R.styleable.Window_windowIsFloating, false)
255                    && !ent.array.getBoolean(
256                    com.android.internal.R.styleable.Window_windowIsTranslucent, false);
257
258            if (!_componentSpecified || _launchedFromUid == Process.myUid()
259                    || _launchedFromUid == 0) {
260                // If we know the system has determined the component, then
261                // we can consider this to be a home activity...
262                if (Intent.ACTION_MAIN.equals(_intent.getAction()) &&
263                        _intent.hasCategory(Intent.CATEGORY_HOME) &&
264                        _intent.getCategories().size() == 1 &&
265                        _intent.getData() == null &&
266                        _intent.getType() == null &&
267                        (intent.getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
268                        !"android".equals(realActivity.getClassName())) {
269                    // This sure looks like a home activity!
270                    // Note the last check is so we don't count the resolver
271                    // activity as being home...  really, we don't care about
272                    // doing anything special with something that comes from
273                    // the core framework package.
274                    isHomeActivity = true;
275                } else {
276                    isHomeActivity = false;
277                }
278            } else {
279                isHomeActivity = false;
280            }
281        } else {
282            realActivity = null;
283            taskAffinity = null;
284            stateNotNeeded = false;
285            baseDir = null;
286            resDir = null;
287            dataDir = null;
288            processName = null;
289            packageName = null;
290            fullscreen = true;
291            isHomeActivity = false;
292        }
293    }
294
295    void addResultLocked(HistoryRecord from, String resultWho,
296            int requestCode, int resultCode,
297            Intent resultData) {
298        ActivityResult r = new ActivityResult(from, resultWho,
299        		requestCode, resultCode, resultData);
300        if (results == null) {
301            results = new ArrayList();
302        }
303        results.add(r);
304    }
305
306    void removeResultsLocked(HistoryRecord from, String resultWho,
307            int requestCode) {
308        if (results != null) {
309            for (int i=results.size()-1; i>=0; i--) {
310                ActivityResult r = (ActivityResult)results.get(i);
311                if (r.mFrom != from) continue;
312                if (r.mResultWho == null) {
313                    if (resultWho != null) continue;
314                } else {
315                    if (!r.mResultWho.equals(resultWho)) continue;
316                }
317                if (r.mRequestCode != requestCode) continue;
318
319                results.remove(i);
320            }
321        }
322    }
323
324    void addNewIntentLocked(Intent intent) {
325        if (newIntents == null) {
326            newIntents = new ArrayList();
327        }
328        newIntents.add(intent);
329    }
330
331    void pauseKeyDispatchingLocked() {
332        if (!keysPaused) {
333            keysPaused = true;
334            service.mWindowManager.pauseKeyDispatching(this);
335        }
336    }
337
338    void resumeKeyDispatchingLocked() {
339        if (keysPaused) {
340            keysPaused = false;
341            service.mWindowManager.resumeKeyDispatching(this);
342        }
343    }
344
345    // IApplicationToken
346
347    public boolean mayFreezeScreenLocked(ProcessRecord app) {
348        // Only freeze the screen if this activity is currently attached to
349        // an application, and that application is not blocked or unresponding.
350        // In any other case, we can't count on getting the screen unfrozen,
351        // so it is best to leave as-is.
352        return app == null || (!app.crashing && !app.notResponding);
353    }
354
355    public void startFreezingScreenLocked(ProcessRecord app, int configChanges) {
356        if (mayFreezeScreenLocked(app)) {
357            service.mWindowManager.startAppFreezingScreen(this, configChanges);
358        }
359    }
360
361    public void stopFreezingScreenLocked(boolean force) {
362        if (force || frozenBeforeDestroy) {
363            frozenBeforeDestroy = false;
364            service.mWindowManager.stopAppFreezingScreen(this, force);
365        }
366    }
367
368    public void windowsVisible() {
369        synchronized(service) {
370            if (startTime != 0) {
371                final long curTime = SystemClock.uptimeMillis();
372                final long thisTime = curTime - startTime;
373                final long totalTime = service.mInitialStartTime != 0
374                        ? (curTime - service.mInitialStartTime) : thisTime;
375                if (ActivityManagerService.SHOW_ACTIVITY_START_TIME) {
376                    EventLog.writeEvent(EventLogTags.ACTIVITY_LAUNCH_TIME,
377                            System.identityHashCode(this), shortComponentName,
378                            thisTime, totalTime);
379                    StringBuilder sb = service.mStringBuilder;
380                    sb.setLength(0);
381                    sb.append("Displayed activity ");
382                    sb.append(shortComponentName);
383                    sb.append(": ");
384                    sb.append(thisTime);
385                    sb.append(" ms (total ");
386                    sb.append(totalTime);
387                    sb.append(" ms)");
388                    Log.i(ActivityManagerService.TAG, sb.toString());
389                }
390                service.reportActivityLaunchedLocked(false, this, thisTime, totalTime);
391                if (totalTime > 0) {
392                    service.mUsageStatsService.noteLaunchTime(realActivity, (int)totalTime);
393                }
394                startTime = 0;
395                service.mInitialStartTime = 0;
396            }
397            service.reportActivityVisibleLocked(this);
398            if (ActivityManagerService.DEBUG_SWITCH) Log.v(
399                    ActivityManagerService.TAG, "windowsVisible(): " + this);
400            if (!nowVisible) {
401                nowVisible = true;
402                if (!idle) {
403                    // Instead of doing the full stop routine here, let's just
404                    // hide any activities we now can, and let them stop when
405                    // the normal idle happens.
406                    service.processStoppingActivitiesLocked(false);
407                } else {
408                    // If this activity was already idle, then we now need to
409                    // make sure we perform the full stop of any activities
410                    // that are waiting to do so.  This is because we won't
411                    // do that while they are still waiting for this one to
412                    // become visible.
413                    final int N = service.mWaitingVisibleActivities.size();
414                    if (N > 0) {
415                        for (int i=0; i<N; i++) {
416                            HistoryRecord r = (HistoryRecord)
417                                service.mWaitingVisibleActivities.get(i);
418                            r.waitingVisible = false;
419                            if (ActivityManagerService.DEBUG_SWITCH) Log.v(
420                                    ActivityManagerService.TAG,
421                                    "Was waiting for visible: " + r);
422                        }
423                        service.mWaitingVisibleActivities.clear();
424                        Message msg = Message.obtain();
425                        msg.what = ActivityManagerService.IDLE_NOW_MSG;
426                        service.mHandler.sendMessage(msg);
427                    }
428                }
429                service.scheduleAppGcsLocked();
430            }
431        }
432    }
433
434    public void windowsGone() {
435        if (ActivityManagerService.DEBUG_SWITCH) Log.v(
436                ActivityManagerService.TAG, "windowsGone(): " + this);
437        nowVisible = false;
438    }
439
440    private HistoryRecord getWaitingHistoryRecordLocked() {
441        // First find the real culprit...  if we are waiting
442        // for another app to start, then we have paused dispatching
443        // for this activity.
444        HistoryRecord r = this;
445        if (r.waitingVisible) {
446            // Hmmm, who might we be waiting for?
447            r = service.mResumedActivity;
448            if (r == null) {
449                r = service.mPausingActivity;
450            }
451            // Both of those null?  Fall back to 'this' again
452            if (r == null) {
453                r = this;
454            }
455        }
456
457        return r;
458    }
459
460    public boolean keyDispatchingTimedOut() {
461        HistoryRecord r;
462        ProcessRecord anrApp = null;
463        synchronized(service) {
464            r = getWaitingHistoryRecordLocked();
465            if (r != null && r.app != null) {
466                if (r.app.debugging) {
467                    return false;
468                }
469
470                if (service.mDidDexOpt) {
471                    // Give more time since we were dexopting.
472                    service.mDidDexOpt = false;
473                    return false;
474                }
475
476                if (r.app.instrumentationClass == null) {
477                    anrApp = r.app;
478                } else {
479                    Bundle info = new Bundle();
480                    info.putString("shortMsg", "keyDispatchingTimedOut");
481                    info.putString("longMsg", "Timed out while dispatching key event");
482                    service.finishInstrumentationLocked(
483                            r.app, Activity.RESULT_CANCELED, info);
484                }
485            }
486        }
487
488        if (anrApp != null) {
489            service.appNotResponding(anrApp, r, this,
490                    "keyDispatchingTimedOut");
491        }
492
493        return true;
494    }
495
496    /** Returns the key dispatching timeout for this application token. */
497    public long getKeyDispatchingTimeout() {
498        synchronized(service) {
499            HistoryRecord r = getWaitingHistoryRecordLocked();
500            if (r == null || r.app == null
501                    || r.app.instrumentationClass == null) {
502                return ActivityManagerService.KEY_DISPATCHING_TIMEOUT;
503            }
504
505            return ActivityManagerService.INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT;
506        }
507    }
508
509    /**
510     * This method will return true if the activity is either visible, is becoming visible, is
511     * currently pausing, or is resumed.
512     */
513    public boolean isInterestingToUserLocked() {
514        return visible || nowVisible || state == ActivityState.PAUSING ||
515                state == ActivityState.RESUMED;
516     }
517
518
519    public String toString() {
520        if (stringName != null) {
521            return stringName;
522        }
523        StringBuilder sb = new StringBuilder(128);
524        sb.append("HistoryRecord{");
525        sb.append(Integer.toHexString(System.identityHashCode(this)));
526        sb.append(' ');
527        sb.append(intent.getComponent().flattenToShortString());
528        sb.append('}');
529        return stringName = sb.toString();
530    }
531}
532