ActivityRecord.java revision 8a4c9721a9e09d20c63381c13fa29bd9f7cbc3e3
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 android.app.ActivityManager.TaskDescription;
20import android.os.PersistableBundle;
21import android.os.Trace;
22
23import com.android.internal.app.ResolverActivity;
24import com.android.internal.util.XmlUtils;
25import com.android.server.AttributeCache;
26import com.android.server.am.ActivityStack.ActivityState;
27import com.android.server.am.ActivityStackSupervisor.ActivityContainer;
28
29import android.app.ActivityOptions;
30import android.app.ResultInfo;
31import android.content.ComponentName;
32import android.content.Intent;
33import android.content.pm.ActivityInfo;
34import android.content.pm.ApplicationInfo;
35import android.content.res.CompatibilityInfo;
36import android.content.res.Configuration;
37import android.graphics.Bitmap;
38import android.graphics.Rect;
39import android.os.Build;
40import android.os.Bundle;
41import android.os.IBinder;
42import android.os.Message;
43import android.os.Process;
44import android.os.RemoteException;
45import android.os.SystemClock;
46import android.os.UserHandle;
47import android.util.EventLog;
48import android.util.Log;
49import android.util.Slog;
50import android.util.TimeUtils;
51import android.view.IApplicationToken;
52import android.view.WindowManager;
53
54import org.xmlpull.v1.XmlPullParser;
55import org.xmlpull.v1.XmlPullParserException;
56import org.xmlpull.v1.XmlSerializer;
57
58import java.io.IOException;
59import java.io.PrintWriter;
60import java.lang.ref.WeakReference;
61import java.util.ArrayList;
62import java.util.HashSet;
63import java.util.Objects;
64
65/**
66 * An entry in the history stack, representing an activity.
67 */
68final class ActivityRecord {
69    static final String TAG = ActivityManagerService.TAG;
70    static final boolean DEBUG_SAVED_STATE = ActivityStackSupervisor.DEBUG_SAVED_STATE;
71    final public static String RECENTS_PACKAGE_NAME = "com.android.systemui.recent";
72
73    private static final String TAG_ACTIVITY = "activity";
74    private static final String ATTR_ID = "id";
75    private static final String TAG_INTENT = "intent";
76    private static final String ATTR_USERID = "user_id";
77    private static final String TAG_PERSISTABLEBUNDLE = "persistable_bundle";
78    private static final String ATTR_LAUNCHEDFROMUID = "launched_from_uid";
79    private static final String ATTR_LAUNCHEDFROMPACKAGE = "launched_from_package";
80    private static final String ATTR_RESOLVEDTYPE = "resolved_type";
81    private static final String ATTR_COMPONENTSPECIFIED = "component_specified";
82    private static final String ATTR_TASKDESCRIPTIONLABEL = "task_description_label";
83    private static final String ATTR_TASKDESCRIPTIONCOLOR = "task_description_color";
84    private static final String ACTIVITY_ICON_SUFFIX = "_activity_icon_";
85
86    final ActivityManagerService service; // owner
87    final IApplicationToken.Stub appToken; // window manager token
88    final ActivityInfo info; // all about me
89    final ApplicationInfo appInfo; // information about activity's app
90    final int launchedFromUid; // always the uid who started the activity.
91    final String launchedFromPackage; // always the package who started the activity.
92    final int userId;          // Which user is this running for?
93    final Intent intent;    // the original intent that generated us
94    final ComponentName realActivity;  // the intent component, or target of an alias.
95    final String shortComponentName; // the short component name of the intent
96    final String resolvedType; // as per original caller;
97    final String packageName; // the package implementing intent's component
98    final String processName; // process where this component wants to run
99    final String taskAffinity; // as per ActivityInfo.taskAffinity
100    final boolean stateNotNeeded; // As per ActivityInfo.flags
101    boolean fullscreen; // covers the full screen?
102    final boolean noDisplay;  // activity is not displayed?
103    final boolean componentSpecified;  // did caller specifiy an explicit component?
104
105    static final int APPLICATION_ACTIVITY_TYPE = 0;
106    static final int HOME_ACTIVITY_TYPE = 1;
107    static final int RECENTS_ACTIVITY_TYPE = 2;
108    int mActivityType;
109
110    CharSequence nonLocalizedLabel;  // the label information from the package mgr.
111    int labelRes;           // the label information from the package mgr.
112    int icon;               // resource identifier of activity's icon.
113    int logo;               // resource identifier of activity's logo.
114    int theme;              // resource identifier of activity's theme.
115    int realTheme;          // actual theme resource we will use, never 0.
116    int windowFlags;        // custom window flags for preview window.
117    TaskRecord task;        // the task this is in.
118    ThumbnailHolder thumbHolder; // where our thumbnails should go.
119    long createTime = System.currentTimeMillis();
120    long displayStartTime;  // when we started launching this activity
121    long fullyDrawnStartTime; // when we started launching this activity
122    long startTime;         // last time this activity was started
123    long lastVisibleTime;   // last time this activity became visible
124    long cpuTimeAtResume;   // the cpu time of host process at the time of resuming activity
125    long pauseTime;         // last time we started pausing the activity
126    long launchTickTime;    // base time for launch tick messages
127    Configuration configuration; // configuration activity was last running in
128    CompatibilityInfo compat;// last used compatibility mode
129    ActivityRecord resultTo; // who started this entry, so will get our reply
130    final String resultWho; // additional identifier for use by resultTo.
131    final int requestCode;  // code given by requester (resultTo)
132    ArrayList<ResultInfo> results; // pending ActivityResult objs we have received
133    HashSet<WeakReference<PendingIntentRecord>> pendingResults; // all pending intents for this act
134    ArrayList<Intent> newIntents; // any pending new intents for single-top mode
135    ActivityOptions pendingOptions; // most recently given options
136    HashSet<ConnectionRecord> connections; // All ConnectionRecord we hold
137    UriPermissionOwner uriPermissions; // current special URI access perms.
138    ProcessRecord app;      // if non-null, hosting application
139    ActivityState state;    // current state we are in
140    Bundle  icicle;         // last saved activity state
141    PersistableBundle persistentState; // last persistently saved activity state
142    boolean frontOfTask;    // is this the root activity of its task?
143    boolean launchFailed;   // set if a launched failed, to abort on 2nd try
144    boolean haveState;      // have we gotten the last activity state?
145    boolean stopped;        // is activity pause finished?
146    boolean delayedResume;  // not yet resumed because of stopped app switches?
147    boolean finishing;      // activity in pending finish list?
148    boolean configDestroy;  // need to destroy due to config change?
149    int configChangeFlags;  // which config values have changed
150    boolean keysPaused;     // has key dispatching been paused for it?
151    int launchMode;         // the launch mode activity attribute.
152    boolean visible;        // does this activity's window need to be shown?
153    boolean sleeping;       // have we told the activity to sleep?
154    boolean waitingVisible; // true if waiting for a new act to become vis
155    boolean nowVisible;     // is this activity's window visible?
156    boolean idle;           // has the activity gone idle?
157    boolean hasBeenLaunched;// has this activity ever been launched?
158    boolean frozenBeforeDestroy;// has been frozen but not yet destroyed.
159    boolean immersive;      // immersive mode (don't interrupt if possible)
160    boolean forceNewConfig; // force re-create with new config next time
161    int launchCount;        // count of launches since last state
162    long lastLaunchTime;    // time of last lauch of this activity
163    ArrayList<ActivityContainer> mChildContainers = new ArrayList<ActivityContainer>();
164
165    String stringName;      // for caching of toString().
166
167    private boolean inHistory;  // are we in the history stack?
168    final ActivityStackSupervisor mStackSupervisor;
169    boolean mStartingWindowShown = false;
170    ActivityContainer mInitialActivityContainer;
171
172    TaskDescription taskDescription; // the recents information for this activity
173
174    void dump(PrintWriter pw, String prefix) {
175        final long now = SystemClock.uptimeMillis();
176        pw.print(prefix); pw.print("packageName="); pw.print(packageName);
177                pw.print(" processName="); pw.println(processName);
178        pw.print(prefix); pw.print("launchedFromUid="); pw.print(launchedFromUid);
179                pw.print(" launchedFromPackage="); pw.print(launchedFromPackage);
180                pw.print(" userId="); pw.println(userId);
181        pw.print(prefix); pw.print("app="); pw.println(app);
182        pw.print(prefix); pw.println(intent.toInsecureStringWithClip());
183        pw.print(prefix); pw.print("frontOfTask="); pw.print(frontOfTask);
184                pw.print(" task="); pw.println(task);
185        pw.print(prefix); pw.print("taskAffinity="); pw.println(taskAffinity);
186        pw.print(prefix); pw.print("realActivity=");
187                pw.println(realActivity.flattenToShortString());
188        if (appInfo != null) {
189            pw.print(prefix); pw.print("baseDir="); pw.println(appInfo.sourceDir);
190            if (!Objects.equals(appInfo.sourceDir, appInfo.publicSourceDir)) {
191                pw.print(prefix); pw.print("resDir="); pw.println(appInfo.publicSourceDir);
192            }
193            pw.print(prefix); pw.print("dataDir="); pw.println(appInfo.dataDir);
194        }
195        pw.print(prefix); pw.print("stateNotNeeded="); pw.print(stateNotNeeded);
196                pw.print(" componentSpecified="); pw.print(componentSpecified);
197                pw.print(" mActivityType="); pw.println(mActivityType);
198        pw.print(prefix); pw.print("compat="); pw.print(compat);
199                pw.print(" labelRes=0x"); pw.print(Integer.toHexString(labelRes));
200                pw.print(" icon=0x"); pw.print(Integer.toHexString(icon));
201                pw.print(" theme=0x"); pw.println(Integer.toHexString(theme));
202        pw.print(prefix); pw.print("config="); pw.println(configuration);
203        if (resultTo != null || resultWho != null) {
204            pw.print(prefix); pw.print("resultTo="); pw.print(resultTo);
205                    pw.print(" resultWho="); pw.print(resultWho);
206                    pw.print(" resultCode="); pw.println(requestCode);
207        }
208        if (results != null) {
209            pw.print(prefix); pw.print("results="); pw.println(results);
210        }
211        if (pendingResults != null && pendingResults.size() > 0) {
212            pw.print(prefix); pw.println("Pending Results:");
213            for (WeakReference<PendingIntentRecord> wpir : pendingResults) {
214                PendingIntentRecord pir = wpir != null ? wpir.get() : null;
215                pw.print(prefix); pw.print("  - ");
216                if (pir == null) {
217                    pw.println("null");
218                } else {
219                    pw.println(pir);
220                    pir.dump(pw, prefix + "    ");
221                }
222            }
223        }
224        if (newIntents != null && newIntents.size() > 0) {
225            pw.print(prefix); pw.println("Pending New Intents:");
226            for (int i=0; i<newIntents.size(); i++) {
227                Intent intent = newIntents.get(i);
228                pw.print(prefix); pw.print("  - ");
229                if (intent == null) {
230                    pw.println("null");
231                } else {
232                    pw.println(intent.toShortString(false, true, false, true));
233                }
234            }
235        }
236        if (pendingOptions != null) {
237            pw.print(prefix); pw.print("pendingOptions="); pw.println(pendingOptions);
238        }
239        if (uriPermissions != null) {
240            uriPermissions.dump(pw, prefix);
241        }
242        pw.print(prefix); pw.print("launchFailed="); pw.print(launchFailed);
243                pw.print(" launchCount="); pw.print(launchCount);
244                pw.print(" lastLaunchTime=");
245                if (lastLaunchTime == 0) pw.print("0");
246                else TimeUtils.formatDuration(lastLaunchTime, now, pw);
247                pw.println();
248        pw.print(prefix); pw.print("haveState="); pw.print(haveState);
249                pw.print(" icicle="); pw.println(icicle);
250        pw.print(prefix); pw.print("state="); pw.print(state);
251                pw.print(" stopped="); pw.print(stopped);
252                pw.print(" delayedResume="); pw.print(delayedResume);
253                pw.print(" finishing="); pw.println(finishing);
254        pw.print(prefix); pw.print("keysPaused="); pw.print(keysPaused);
255                pw.print(" inHistory="); pw.print(inHistory);
256                pw.print(" visible="); pw.print(visible);
257                pw.print(" sleeping="); pw.print(sleeping);
258                pw.print(" idle="); pw.println(idle);
259        pw.print(prefix); pw.print("fullscreen="); pw.print(fullscreen);
260                pw.print(" noDisplay="); pw.print(noDisplay);
261                pw.print(" immersive="); pw.print(immersive);
262                pw.print(" launchMode="); pw.println(launchMode);
263        pw.print(prefix); pw.print("frozenBeforeDestroy="); pw.print(frozenBeforeDestroy);
264                pw.print(" forceNewConfig="); pw.println(forceNewConfig);
265        pw.print(prefix); pw.print("mActivityType=");
266                pw.println(activityTypeToString(mActivityType));
267        pw.print(prefix); pw.print("thumbHolder: ");
268                pw.print(Integer.toHexString(System.identityHashCode(thumbHolder)));
269                if (thumbHolder != null) {
270                    pw.print(" bm="); pw.print(thumbHolder.lastThumbnail);
271                    pw.print(" desc="); pw.print(thumbHolder.lastDescription);
272                }
273                pw.println();
274        if (displayStartTime != 0 || startTime != 0) {
275            pw.print(prefix); pw.print("displayStartTime=");
276                    if (displayStartTime == 0) pw.print("0");
277                    else TimeUtils.formatDuration(displayStartTime, now, pw);
278                    pw.print(" startTime=");
279                    if (startTime == 0) pw.print("0");
280                    else TimeUtils.formatDuration(startTime, now, pw);
281                    pw.println();
282        }
283        if (lastVisibleTime != 0 || waitingVisible || nowVisible) {
284            pw.print(prefix); pw.print("waitingVisible="); pw.print(waitingVisible);
285                    pw.print(" nowVisible="); pw.print(nowVisible);
286                    pw.print(" lastVisibleTime=");
287                    if (lastVisibleTime == 0) pw.print("0");
288                    else TimeUtils.formatDuration(lastVisibleTime, now, pw);
289                    pw.println();
290        }
291        if (configDestroy || configChangeFlags != 0) {
292            pw.print(prefix); pw.print("configDestroy="); pw.print(configDestroy);
293                    pw.print(" configChangeFlags=");
294                    pw.println(Integer.toHexString(configChangeFlags));
295        }
296        if (connections != null) {
297            pw.print(prefix); pw.print("connections="); pw.println(connections);
298        }
299    }
300
301    static class Token extends IApplicationToken.Stub {
302        final WeakReference<ActivityRecord> weakActivity;
303
304        Token(ActivityRecord activity) {
305            weakActivity = new WeakReference<ActivityRecord>(activity);
306        }
307
308        @Override public void windowsDrawn() {
309            ActivityRecord activity = weakActivity.get();
310            if (activity != null) {
311                activity.windowsDrawn();
312            }
313        }
314
315        @Override public void windowsVisible() {
316            ActivityRecord activity = weakActivity.get();
317            if (activity != null) {
318                activity.windowsVisible();
319            }
320        }
321
322        @Override public void windowsGone() {
323            ActivityRecord activity = weakActivity.get();
324            if (activity != null) {
325                activity.windowsGone();
326            }
327        }
328
329        @Override public boolean keyDispatchingTimedOut(String reason) {
330            ActivityRecord activity = weakActivity.get();
331            return activity != null && activity.keyDispatchingTimedOut(reason);
332        }
333
334        @Override public long getKeyDispatchingTimeout() {
335            ActivityRecord activity = weakActivity.get();
336            if (activity != null) {
337                return activity.getKeyDispatchingTimeout();
338            }
339            return 0;
340        }
341
342        @Override
343        public String toString() {
344            StringBuilder sb = new StringBuilder(128);
345            sb.append("Token{");
346            sb.append(Integer.toHexString(System.identityHashCode(this)));
347            sb.append(' ');
348            sb.append(weakActivity.get());
349            sb.append('}');
350            return sb.toString();
351        }
352    }
353
354    static ActivityRecord forToken(IBinder token) {
355        try {
356            return token != null ? ((Token)token).weakActivity.get() : null;
357        } catch (ClassCastException e) {
358            Slog.w(ActivityManagerService.TAG, "Bad activity token: " + token, e);
359            return null;
360        }
361    }
362
363    boolean isNotResolverActivity() {
364        return !ResolverActivity.class.getName().equals(realActivity.getClassName());
365    }
366
367    ActivityRecord(ActivityManagerService _service, ProcessRecord _caller,
368            int _launchedFromUid, String _launchedFromPackage, Intent _intent, String _resolvedType,
369            ActivityInfo aInfo, Configuration _configuration,
370            ActivityRecord _resultTo, String _resultWho, int _reqCode,
371            boolean _componentSpecified, ActivityStackSupervisor supervisor,
372            ActivityContainer container, Bundle options) {
373        service = _service;
374        appToken = new Token(this);
375        info = aInfo;
376        launchedFromUid = _launchedFromUid;
377        launchedFromPackage = _launchedFromPackage;
378        userId = UserHandle.getUserId(aInfo.applicationInfo.uid);
379        intent = _intent;
380        shortComponentName = _intent.getComponent().flattenToShortString();
381        resolvedType = _resolvedType;
382        componentSpecified = _componentSpecified;
383        configuration = _configuration;
384        resultTo = _resultTo;
385        resultWho = _resultWho;
386        requestCode = _reqCode;
387        state = ActivityState.INITIALIZING;
388        frontOfTask = false;
389        launchFailed = false;
390        stopped = false;
391        delayedResume = false;
392        finishing = false;
393        configDestroy = false;
394        keysPaused = false;
395        inHistory = false;
396        visible = true;
397        waitingVisible = false;
398        nowVisible = false;
399        idle = false;
400        hasBeenLaunched = false;
401        mStackSupervisor = supervisor;
402        mInitialActivityContainer = container;
403        if (options != null) {
404            pendingOptions = new ActivityOptions(options);
405        }
406
407        // This starts out true, since the initial state of an activity
408        // is that we have everything, and we shouldn't never consider it
409        // lacking in state to be removed if it dies.
410        haveState = true;
411
412        if (aInfo != null) {
413            if (aInfo.targetActivity == null
414                    || aInfo.launchMode == ActivityInfo.LAUNCH_MULTIPLE
415                    || aInfo.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP) {
416                realActivity = _intent.getComponent();
417            } else {
418                realActivity = new ComponentName(aInfo.packageName,
419                        aInfo.targetActivity);
420            }
421            taskAffinity = aInfo.taskAffinity;
422            stateNotNeeded = (aInfo.flags&
423                    ActivityInfo.FLAG_STATE_NOT_NEEDED) != 0;
424            appInfo = aInfo.applicationInfo;
425            nonLocalizedLabel = aInfo.nonLocalizedLabel;
426            labelRes = aInfo.labelRes;
427            if (nonLocalizedLabel == null && labelRes == 0) {
428                ApplicationInfo app = aInfo.applicationInfo;
429                nonLocalizedLabel = app.nonLocalizedLabel;
430                labelRes = app.labelRes;
431            }
432            icon = aInfo.getIconResource();
433            logo = aInfo.getLogoResource();
434            theme = aInfo.getThemeResource();
435            realTheme = theme;
436            if (realTheme == 0) {
437                realTheme = aInfo.applicationInfo.targetSdkVersion
438                        < Build.VERSION_CODES.HONEYCOMB
439                        ? android.R.style.Theme
440                        : android.R.style.Theme_Holo;
441            }
442            if ((aInfo.flags&ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0) {
443                windowFlags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
444            }
445            if ((aInfo.flags&ActivityInfo.FLAG_MULTIPROCESS) != 0
446                    && _caller != null
447                    && (aInfo.applicationInfo.uid == Process.SYSTEM_UID
448                            || aInfo.applicationInfo.uid == _caller.info.uid)) {
449                processName = _caller.processName;
450            } else {
451                processName = aInfo.processName;
452            }
453
454            if (intent != null && (aInfo.flags & ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS) != 0) {
455                intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
456            }
457
458            packageName = aInfo.applicationInfo.packageName;
459            launchMode = aInfo.launchMode;
460
461            AttributeCache.Entry ent = AttributeCache.instance().get(packageName,
462                    realTheme, com.android.internal.R.styleable.Window, userId);
463            fullscreen = ent != null && !ent.array.getBoolean(
464                    com.android.internal.R.styleable.Window_windowIsFloating, false)
465                    && !ent.array.getBoolean(
466                    com.android.internal.R.styleable.Window_windowIsTranslucent, false);
467            noDisplay = ent != null && ent.array.getBoolean(
468                    com.android.internal.R.styleable.Window_windowNoDisplay, false);
469
470            if ((!_componentSpecified || _launchedFromUid == Process.myUid()
471                    || _launchedFromUid == 0) &&
472                    Intent.ACTION_MAIN.equals(_intent.getAction()) &&
473                    _intent.hasCategory(Intent.CATEGORY_HOME) &&
474                    _intent.getCategories().size() == 1 &&
475                    _intent.getData() == null &&
476                    _intent.getType() == null &&
477                    (intent.getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
478                    isNotResolverActivity()) {
479                // This sure looks like a home activity!
480                mActivityType = HOME_ACTIVITY_TYPE;
481            } else if (realActivity.getClassName().contains(RECENTS_PACKAGE_NAME)) {
482                mActivityType = RECENTS_ACTIVITY_TYPE;
483            } else {
484                mActivityType = APPLICATION_ACTIVITY_TYPE;
485            }
486
487            immersive = (aInfo.flags & ActivityInfo.FLAG_IMMERSIVE) != 0;
488        } else {
489            realActivity = null;
490            taskAffinity = null;
491            stateNotNeeded = false;
492            appInfo = null;
493            processName = null;
494            packageName = null;
495            fullscreen = true;
496            noDisplay = false;
497            mActivityType = APPLICATION_ACTIVITY_TYPE;
498            immersive = false;
499        }
500    }
501
502    void setTask(TaskRecord newTask, ThumbnailHolder newThumbHolder, boolean isRoot) {
503        if (task != null && task.removeActivity(this)) {
504            if (task != newTask) {
505                task.stack.removeTask(task);
506            } else {
507                Slog.d(TAG, "!!! REMOVE THIS LOG !!! setTask: nearly removed stack=" +
508                        (newTask == null ? null : newTask.stack));
509            }
510        }
511        if (newThumbHolder == null) {
512            newThumbHolder = newTask;
513        }
514        task = newTask;
515        if (!isRoot && (intent.getFlags()&Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) {
516            // This is the start of a new sub-task.
517            if (thumbHolder == null) {
518                thumbHolder = new ThumbnailHolder();
519            }
520        } else {
521            thumbHolder = newThumbHolder;
522        }
523    }
524
525    boolean changeWindowTranslucency(boolean toOpaque) {
526        if (fullscreen == toOpaque) {
527            return false;
528        }
529
530        // Keep track of the number of fullscreen activities in this task.
531        task.numFullscreen += toOpaque ? +1 : -1;
532
533        fullscreen = toOpaque;
534        return true;
535    }
536
537    void putInHistory() {
538        if (!inHistory) {
539            inHistory = true;
540        }
541    }
542
543    void takeFromHistory() {
544        if (inHistory) {
545            inHistory = false;
546            if (task != null && !finishing) {
547                task = null;
548            }
549            clearOptionsLocked();
550        }
551    }
552
553    boolean isInHistory() {
554        return inHistory;
555    }
556
557    boolean isHomeActivity() {
558        return mActivityType == HOME_ACTIVITY_TYPE;
559    }
560
561    boolean isRecentsActivity() {
562        return mActivityType == RECENTS_ACTIVITY_TYPE;
563    }
564
565    boolean isApplicationActivity() {
566        return mActivityType == APPLICATION_ACTIVITY_TYPE;
567    }
568
569    boolean isPersistable() {
570        return (info.flags & ActivityInfo.FLAG_PERSISTABLE) != 0;
571    }
572
573    void makeFinishing() {
574        if (!finishing) {
575            finishing = true;
576            if (stopped) {
577                clearOptionsLocked();
578            }
579        }
580    }
581
582    boolean isRootActivity() {
583        final ArrayList<ActivityRecord> activities = task.mActivities;
584        return activities.size() == 0 || this == activities.get(0);
585    }
586
587    UriPermissionOwner getUriPermissionsLocked() {
588        if (uriPermissions == null) {
589            uriPermissions = new UriPermissionOwner(service, this);
590        }
591        return uriPermissions;
592    }
593
594    void addResultLocked(ActivityRecord from, String resultWho,
595            int requestCode, int resultCode,
596            Intent resultData) {
597        ActivityResult r = new ActivityResult(from, resultWho,
598                requestCode, resultCode, resultData);
599        if (results == null) {
600            results = new ArrayList<ResultInfo>();
601        }
602        results.add(r);
603    }
604
605    void removeResultsLocked(ActivityRecord from, String resultWho,
606            int requestCode) {
607        if (results != null) {
608            for (int i=results.size()-1; i>=0; i--) {
609                ActivityResult r = (ActivityResult)results.get(i);
610                if (r.mFrom != from) continue;
611                if (r.mResultWho == null) {
612                    if (resultWho != null) continue;
613                } else {
614                    if (!r.mResultWho.equals(resultWho)) continue;
615                }
616                if (r.mRequestCode != requestCode) continue;
617
618                results.remove(i);
619            }
620        }
621    }
622
623    void addNewIntentLocked(Intent intent) {
624        if (newIntents == null) {
625            newIntents = new ArrayList<Intent>();
626        }
627        newIntents.add(intent);
628    }
629
630    /**
631     * Deliver a new Intent to an existing activity, so that its onNewIntent()
632     * method will be called at the proper time.
633     */
634    final void deliverNewIntentLocked(int callingUid, Intent intent) {
635        // The activity now gets access to the data associated with this Intent.
636        service.grantUriPermissionFromIntentLocked(callingUid, packageName,
637                intent, getUriPermissionsLocked(), userId);
638        // We want to immediately deliver the intent to the activity if
639        // it is currently the top resumed activity...  however, if the
640        // device is sleeping, then all activities are stopped, so in that
641        // case we will deliver it if this is the current top activity on its
642        // stack.
643        boolean unsent = true;
644        if ((state == ActivityState.RESUMED || (service.isSleeping()
645                        && task.stack.topRunningActivityLocked(null) == this))
646                && app != null && app.thread != null) {
647            try {
648                ArrayList<Intent> ar = new ArrayList<Intent>();
649                intent = new Intent(intent);
650                ar.add(intent);
651                app.thread.scheduleNewIntent(ar, appToken);
652                unsent = false;
653            } catch (RemoteException e) {
654                Slog.w(ActivityManagerService.TAG,
655                        "Exception thrown sending new intent to " + this, e);
656            } catch (NullPointerException e) {
657                Slog.w(ActivityManagerService.TAG,
658                        "Exception thrown sending new intent to " + this, e);
659            }
660        }
661        if (unsent) {
662            addNewIntentLocked(new Intent(intent));
663        }
664    }
665
666    void updateOptionsLocked(Bundle options) {
667        if (options != null) {
668            if (pendingOptions != null) {
669                pendingOptions.abort();
670            }
671            pendingOptions = new ActivityOptions(options);
672        }
673    }
674
675    void updateOptionsLocked(ActivityOptions options) {
676        if (options != null) {
677            if (pendingOptions != null) {
678                pendingOptions.abort();
679            }
680            pendingOptions = options;
681        }
682    }
683
684    void applyOptionsLocked() {
685        if (pendingOptions != null
686                && pendingOptions.getAnimationType() != ActivityOptions.ANIM_SCENE_TRANSITION) {
687            final int animationType = pendingOptions.getAnimationType();
688            switch (animationType) {
689                case ActivityOptions.ANIM_CUSTOM:
690                    service.mWindowManager.overridePendingAppTransition(
691                            pendingOptions.getPackageName(),
692                            pendingOptions.getCustomEnterResId(),
693                            pendingOptions.getCustomExitResId(),
694                            pendingOptions.getOnAnimationStartListener());
695                    break;
696                case ActivityOptions.ANIM_SCALE_UP:
697                    service.mWindowManager.overridePendingAppTransitionScaleUp(
698                            pendingOptions.getStartX(), pendingOptions.getStartY(),
699                            pendingOptions.getStartWidth(), pendingOptions.getStartHeight());
700                    if (intent.getSourceBounds() == null) {
701                        intent.setSourceBounds(new Rect(pendingOptions.getStartX(),
702                                pendingOptions.getStartY(),
703                                pendingOptions.getStartX()+pendingOptions.getStartWidth(),
704                                pendingOptions.getStartY()+pendingOptions.getStartHeight()));
705                    }
706                    break;
707                case ActivityOptions.ANIM_THUMBNAIL_SCALE_UP:
708                case ActivityOptions.ANIM_THUMBNAIL_SCALE_DOWN:
709                    boolean scaleUp = (animationType == ActivityOptions.ANIM_THUMBNAIL_SCALE_UP);
710                    service.mWindowManager.overridePendingAppTransitionThumb(
711                            pendingOptions.getThumbnail(),
712                            pendingOptions.getStartX(), pendingOptions.getStartY(),
713                            pendingOptions.getOnAnimationStartListener(),
714                            scaleUp);
715                    if (intent.getSourceBounds() == null) {
716                        intent.setSourceBounds(new Rect(pendingOptions.getStartX(),
717                                pendingOptions.getStartY(),
718                                pendingOptions.getStartX()
719                                        + pendingOptions.getThumbnail().getWidth(),
720                                pendingOptions.getStartY()
721                                        + pendingOptions.getThumbnail().getHeight()));
722                    }
723                    break;
724                default:
725                    Slog.e(TAG, "applyOptionsLocked: Unknown animationType=" + animationType);
726                    break;
727            }
728            pendingOptions = null;
729        }
730    }
731
732    ActivityOptions getOptionsForTargetActivityLocked() {
733        return pendingOptions != null ? pendingOptions.forTargetActivity() : null;
734    }
735
736    void clearOptionsLocked() {
737        if (pendingOptions != null) {
738            pendingOptions.abort();
739            pendingOptions = null;
740        }
741    }
742
743    ActivityOptions takeOptionsLocked() {
744        ActivityOptions opts = pendingOptions;
745        pendingOptions = null;
746        return opts;
747    }
748
749    void removeUriPermissionsLocked() {
750        if (uriPermissions != null) {
751            uriPermissions.removeUriPermissionsLocked();
752            uriPermissions = null;
753        }
754    }
755
756    void pauseKeyDispatchingLocked() {
757        if (!keysPaused) {
758            keysPaused = true;
759            service.mWindowManager.pauseKeyDispatching(appToken);
760        }
761    }
762
763    void resumeKeyDispatchingLocked() {
764        if (keysPaused) {
765            keysPaused = false;
766            service.mWindowManager.resumeKeyDispatching(appToken);
767        }
768    }
769
770    void updateThumbnail(Bitmap newThumbnail, CharSequence description) {
771        if (thumbHolder != null) {
772            if (newThumbnail != null) {
773                if (ActivityManagerService.DEBUG_THUMBNAILS) Slog.i(ActivityManagerService.TAG,
774                        "Setting thumbnail of " + this + " holder " + thumbHolder
775                        + " to " + newThumbnail);
776                thumbHolder.lastThumbnail = newThumbnail;
777                if (isPersistable()) {
778                    mStackSupervisor.mService.notifyTaskPersisterLocked(task, false);
779                }
780            }
781            thumbHolder.lastDescription = description;
782        }
783    }
784
785    void startLaunchTickingLocked() {
786        if (ActivityManagerService.IS_USER_BUILD) {
787            return;
788        }
789        if (launchTickTime == 0) {
790            launchTickTime = SystemClock.uptimeMillis();
791            continueLaunchTickingLocked();
792        }
793    }
794
795    boolean continueLaunchTickingLocked() {
796        if (launchTickTime != 0) {
797            final ActivityStack stack = task.stack;
798            Message msg = stack.mHandler.obtainMessage(ActivityStack.LAUNCH_TICK_MSG, this);
799            stack.mHandler.removeMessages(ActivityStack.LAUNCH_TICK_MSG);
800            stack.mHandler.sendMessageDelayed(msg, ActivityStack.LAUNCH_TICK);
801            return true;
802        }
803        return false;
804    }
805
806    void finishLaunchTickingLocked() {
807        launchTickTime = 0;
808        task.stack.mHandler.removeMessages(ActivityStack.LAUNCH_TICK_MSG);
809    }
810
811    // IApplicationToken
812
813    public boolean mayFreezeScreenLocked(ProcessRecord app) {
814        // Only freeze the screen if this activity is currently attached to
815        // an application, and that application is not blocked or unresponding.
816        // In any other case, we can't count on getting the screen unfrozen,
817        // so it is best to leave as-is.
818        return app != null && !app.crashing && !app.notResponding;
819    }
820
821    public void startFreezingScreenLocked(ProcessRecord app, int configChanges) {
822        if (mayFreezeScreenLocked(app)) {
823            service.mWindowManager.startAppFreezingScreen(appToken, configChanges);
824        }
825    }
826
827    public void stopFreezingScreenLocked(boolean force) {
828        if (force || frozenBeforeDestroy) {
829            frozenBeforeDestroy = false;
830            service.mWindowManager.stopAppFreezingScreen(appToken, force);
831        }
832    }
833
834    public void reportFullyDrawnLocked() {
835        final long curTime = SystemClock.uptimeMillis();
836        if (displayStartTime != 0) {
837            reportLaunchTimeLocked(curTime);
838        }
839        if (fullyDrawnStartTime != 0) {
840            final ActivityStack stack = task.stack;
841            final long thisTime = curTime - fullyDrawnStartTime;
842            final long totalTime = stack.mFullyDrawnStartTime != 0
843                    ? (curTime - stack.mFullyDrawnStartTime) : thisTime;
844            if (ActivityManagerService.SHOW_ACTIVITY_START_TIME) {
845                Trace.asyncTraceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER, "drawing", 0);
846                EventLog.writeEvent(EventLogTags.AM_ACTIVITY_FULLY_DRAWN_TIME,
847                        userId, System.identityHashCode(this), shortComponentName,
848                        thisTime, totalTime);
849                StringBuilder sb = service.mStringBuilder;
850                sb.setLength(0);
851                sb.append("Fully drawn ");
852                sb.append(shortComponentName);
853                sb.append(": ");
854                TimeUtils.formatDuration(thisTime, sb);
855                if (thisTime != totalTime) {
856                    sb.append(" (total ");
857                    TimeUtils.formatDuration(totalTime, sb);
858                    sb.append(")");
859                }
860                Log.i(ActivityManagerService.TAG, sb.toString());
861            }
862            if (totalTime > 0) {
863                service.mUsageStatsService.noteFullyDrawnTime(realActivity, (int) totalTime);
864            }
865            fullyDrawnStartTime = 0;
866            stack.mFullyDrawnStartTime = 0;
867        }
868    }
869
870    private void reportLaunchTimeLocked(final long curTime) {
871        final ActivityStack stack = task.stack;
872        final long thisTime = curTime - displayStartTime;
873        final long totalTime = stack.mLaunchStartTime != 0
874                ? (curTime - stack.mLaunchStartTime) : thisTime;
875        if (ActivityManagerService.SHOW_ACTIVITY_START_TIME) {
876            Trace.asyncTraceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER, "launching", 0);
877            EventLog.writeEvent(EventLogTags.AM_ACTIVITY_LAUNCH_TIME,
878                    userId, System.identityHashCode(this), shortComponentName,
879                    thisTime, totalTime);
880            StringBuilder sb = service.mStringBuilder;
881            sb.setLength(0);
882            sb.append("Displayed ");
883            sb.append(shortComponentName);
884            sb.append(": ");
885            TimeUtils.formatDuration(thisTime, sb);
886            if (thisTime != totalTime) {
887                sb.append(" (total ");
888                TimeUtils.formatDuration(totalTime, sb);
889                sb.append(")");
890            }
891            Log.i(ActivityManagerService.TAG, sb.toString());
892        }
893        mStackSupervisor.reportActivityLaunchedLocked(false, this, thisTime, totalTime);
894        if (totalTime > 0) {
895            service.mUsageStatsService.noteLaunchTime(realActivity, (int)totalTime);
896        }
897        displayStartTime = 0;
898        stack.mLaunchStartTime = 0;
899    }
900
901    public void windowsDrawn() {
902        synchronized(service) {
903            if (displayStartTime != 0) {
904                reportLaunchTimeLocked(SystemClock.uptimeMillis());
905            }
906            startTime = 0;
907            finishLaunchTickingLocked();
908            if (task != null) {
909                task.hasBeenVisible = true;
910            }
911        }
912    }
913
914    public void windowsVisible() {
915        synchronized(service) {
916            mStackSupervisor.reportActivityVisibleLocked(this);
917            if (ActivityManagerService.DEBUG_SWITCH) Log.v(
918                    ActivityManagerService.TAG, "windowsVisible(): " + this);
919            if (!nowVisible) {
920                nowVisible = true;
921                lastVisibleTime = SystemClock.uptimeMillis();
922                if (!idle) {
923                    // Instead of doing the full stop routine here, let's just
924                    // hide any activities we now can, and let them stop when
925                    // the normal idle happens.
926                    mStackSupervisor.processStoppingActivitiesLocked(false);
927                } else {
928                    // If this activity was already idle, then we now need to
929                    // make sure we perform the full stop of any activities
930                    // that are waiting to do so.  This is because we won't
931                    // do that while they are still waiting for this one to
932                    // become visible.
933                    final int N = mStackSupervisor.mWaitingVisibleActivities.size();
934                    if (N > 0) {
935                        for (int i=0; i<N; i++) {
936                            ActivityRecord r = mStackSupervisor.mWaitingVisibleActivities.get(i);
937                            r.waitingVisible = false;
938                            if (ActivityManagerService.DEBUG_SWITCH) Log.v(
939                                    ActivityManagerService.TAG,
940                                    "Was waiting for visible: " + r);
941                        }
942                        mStackSupervisor.mWaitingVisibleActivities.clear();
943                        mStackSupervisor.scheduleIdleLocked();
944                    }
945                }
946                service.scheduleAppGcsLocked();
947            }
948        }
949    }
950
951    public void windowsGone() {
952        if (ActivityManagerService.DEBUG_SWITCH) Log.v(
953                ActivityManagerService.TAG, "windowsGone(): " + this);
954        nowVisible = false;
955    }
956
957    private ActivityRecord getWaitingHistoryRecordLocked() {
958        // First find the real culprit...  if we are waiting
959        // for another app to start, then we have paused dispatching
960        // for this activity.
961        ActivityRecord r = this;
962        if (r.waitingVisible) {
963            final ActivityStack stack = mStackSupervisor.getFocusedStack();
964            // Hmmm, who might we be waiting for?
965            r = stack.mResumedActivity;
966            if (r == null) {
967                r = stack.mPausingActivity;
968            }
969            // Both of those null?  Fall back to 'this' again
970            if (r == null) {
971                r = this;
972            }
973        }
974
975        return r;
976    }
977
978    public boolean keyDispatchingTimedOut(String reason) {
979        ActivityRecord r;
980        ProcessRecord anrApp;
981        synchronized(service) {
982            r = getWaitingHistoryRecordLocked();
983            anrApp = r != null ? r.app : null;
984        }
985        return service.inputDispatchingTimedOut(anrApp, r, this, false, reason);
986    }
987
988    /** Returns the key dispatching timeout for this application token. */
989    public long getKeyDispatchingTimeout() {
990        synchronized(service) {
991            ActivityRecord r = getWaitingHistoryRecordLocked();
992            return ActivityManagerService.getInputDispatchingTimeoutLocked(r);
993        }
994    }
995
996    /**
997     * This method will return true if the activity is either visible, is becoming visible, is
998     * currently pausing, or is resumed.
999     */
1000    public boolean isInterestingToUserLocked() {
1001        return visible || nowVisible || state == ActivityState.PAUSING ||
1002                state == ActivityState.RESUMED;
1003    }
1004
1005    public void setSleeping(boolean _sleeping) {
1006        if (sleeping == _sleeping) {
1007            return;
1008        }
1009        if (app != null && app.thread != null) {
1010            try {
1011                app.thread.scheduleSleeping(appToken, _sleeping);
1012                if (_sleeping && !mStackSupervisor.mGoingToSleepActivities.contains(this)) {
1013                    mStackSupervisor.mGoingToSleepActivities.add(this);
1014                }
1015                sleeping = _sleeping;
1016            } catch (RemoteException e) {
1017                Slog.w(TAG, "Exception thrown when sleeping: " + intent.getComponent(), e);
1018            }
1019        }
1020    }
1021
1022    static void activityResumedLocked(IBinder token) {
1023        final ActivityRecord r = ActivityRecord.forToken(token);
1024        if (DEBUG_SAVED_STATE) Slog.i(TAG, "Resumed activity; dropping state of: " + r);
1025        r.icicle = null;
1026        r.haveState = false;
1027    }
1028
1029    static int getTaskForActivityLocked(IBinder token, boolean onlyRoot) {
1030        final ActivityRecord r = ActivityRecord.forToken(token);
1031        if (r == null) {
1032            return -1;
1033        }
1034        final TaskRecord task = r.task;
1035        switch (task.mActivities.indexOf(r)) {
1036            case -1: return -1;
1037            case 0: return task.taskId;
1038            default: return onlyRoot ? -1 : task.taskId;
1039        }
1040    }
1041
1042    static ActivityRecord isInStackLocked(IBinder token) {
1043        final ActivityRecord r = ActivityRecord.forToken(token);
1044        if (r != null) {
1045            return r.task.stack.isInStackLocked(token);
1046        }
1047        return null;
1048    }
1049
1050    static ActivityStack getStackLocked(IBinder token) {
1051        final ActivityRecord r = ActivityRecord.isInStackLocked(token);
1052        if (r != null) {
1053            return r.task.stack;
1054        }
1055        return null;
1056    }
1057
1058    void saveToXml(XmlSerializer out) throws IOException, XmlPullParserException {
1059        out.attribute(null, ATTR_ID, String.valueOf(createTime));
1060        out.attribute(null, ATTR_LAUNCHEDFROMUID, String.valueOf(launchedFromUid));
1061        if (launchedFromPackage != null) {
1062            out.attribute(null, ATTR_LAUNCHEDFROMPACKAGE, launchedFromPackage);
1063        }
1064        if (resolvedType != null) {
1065            out.attribute(null, ATTR_RESOLVEDTYPE, resolvedType);
1066        }
1067        out.attribute(null, ATTR_COMPONENTSPECIFIED, String.valueOf(componentSpecified));
1068        out.attribute(null, ATTR_USERID, String.valueOf(userId));
1069        if (taskDescription != null) {
1070            final String label = taskDescription.getLabel();
1071            if (label != null) {
1072                out.attribute(null, ATTR_TASKDESCRIPTIONLABEL, label);
1073            }
1074            final int colorPrimary = taskDescription.getPrimaryColor();
1075            if (colorPrimary != 0) {
1076                out.attribute(null, ATTR_TASKDESCRIPTIONCOLOR, Integer.toHexString(colorPrimary));
1077            }
1078            final Bitmap icon = taskDescription.getIcon();
1079            if (icon != null) {
1080                TaskPersister.saveImage(icon, String.valueOf(task.taskId) + ACTIVITY_ICON_SUFFIX +
1081                        createTime);
1082            }
1083        }
1084
1085        out.startTag(null, TAG_INTENT);
1086        intent.saveToXml(out);
1087        out.endTag(null, TAG_INTENT);
1088
1089        if (isPersistable() && persistentState != null) {
1090            out.startTag(null, TAG_PERSISTABLEBUNDLE);
1091            persistentState.saveToXml(out);
1092            out.endTag(null, TAG_PERSISTABLEBUNDLE);
1093        }
1094    }
1095
1096    static ActivityRecord restoreFromXml(XmlPullParser in, int taskId,
1097            ActivityStackSupervisor stackSupervisor) throws IOException, XmlPullParserException {
1098        Intent intent = null;
1099        PersistableBundle persistentState = null;
1100        int launchedFromUid = 0;
1101        String launchedFromPackage = null;
1102        String resolvedType = null;
1103        boolean componentSpecified = false;
1104        int userId = 0;
1105        String activityLabel = null;
1106        int activityColor = 0;
1107        long createTime = -1;
1108        final int outerDepth = in.getDepth();
1109
1110        for (int attrNdx = in.getAttributeCount() - 1; attrNdx >= 0; --attrNdx) {
1111            final String attrName = in.getAttributeName(attrNdx);
1112            final String attrValue = in.getAttributeValue(attrNdx);
1113            if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "ActivityRecord: attribute name=" +
1114                    attrName + " value=" + attrValue);
1115            if (ATTR_ID.equals(attrName)) {
1116                createTime = Long.valueOf(attrValue);
1117            } else if (ATTR_LAUNCHEDFROMUID.equals(attrName)) {
1118                launchedFromUid = Integer.valueOf(attrValue);
1119            } else if (ATTR_LAUNCHEDFROMPACKAGE.equals(attrName)) {
1120                launchedFromPackage = attrValue;
1121            } else if (ATTR_RESOLVEDTYPE.equals(attrName)) {
1122                resolvedType = attrValue;
1123            } else if (ATTR_COMPONENTSPECIFIED.equals(attrName)) {
1124                componentSpecified = Boolean.valueOf(attrValue);
1125            } else if (ATTR_USERID.equals(attrName)) {
1126                userId = Integer.valueOf(attrValue);
1127            } else if (ATTR_TASKDESCRIPTIONLABEL.equals(attrName)) {
1128                activityLabel = attrValue;
1129            } else if (ATTR_TASKDESCRIPTIONCOLOR.equals(attrName)) {
1130                activityColor = (int) Long.parseLong(attrValue, 16);
1131            } else {
1132                Log.d(TAG, "Unknown ActivityRecord attribute=" + attrName);
1133            }
1134        }
1135
1136        int event;
1137        while (((event = in.next()) != XmlPullParser.END_DOCUMENT) &&
1138                (event != XmlPullParser.END_TAG || in.getDepth() < outerDepth)) {
1139            if (event == XmlPullParser.START_TAG) {
1140                final String name = in.getName();
1141                if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG,
1142                        "ActivityRecord: START_TAG name=" + name);
1143                if (TAG_INTENT.equals(name)) {
1144                    intent = Intent.restoreFromXml(in);
1145                    if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG,
1146                            "ActivityRecord: intent=" + intent);
1147                } else if (TAG_PERSISTABLEBUNDLE.equals(name)) {
1148                    persistentState = PersistableBundle.restoreFromXml(in);
1149                    if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG,
1150                            "ActivityRecord: persistentState=" + persistentState);
1151                } else {
1152                    Slog.w(TAG, "restoreActivity: unexpected name=" + name);
1153                    XmlUtils.skipCurrentTag(in);
1154                }
1155            }
1156        }
1157
1158        if (intent == null) {
1159            throw new XmlPullParserException("restoreActivity error intent=" + intent);
1160        }
1161
1162        final ActivityManagerService service = stackSupervisor.mService;
1163        final ActivityInfo aInfo = stackSupervisor.resolveActivity(intent, resolvedType, 0, null,
1164                null, userId);
1165        if (aInfo == null) {
1166            throw new XmlPullParserException("restoreActivity resolver error.");
1167        }
1168        final ActivityRecord r = new ActivityRecord(service, /*caller*/null, launchedFromUid,
1169                launchedFromPackage, intent, resolvedType, aInfo, service.getConfiguration(),
1170                null, null, 0, componentSpecified, stackSupervisor, null, null);
1171
1172        r.persistentState = persistentState;
1173
1174        Bitmap icon = null;
1175        if (createTime >= 0) {
1176            icon = TaskPersister.restoreImage(String.valueOf(taskId) + ACTIVITY_ICON_SUFFIX +
1177                    createTime);
1178        }
1179        r.taskDescription = new TaskDescription(activityLabel, icon, activityColor);
1180        r.createTime = createTime;
1181
1182        return r;
1183    }
1184
1185    private static String activityTypeToString(int type) {
1186        switch (type) {
1187            case APPLICATION_ACTIVITY_TYPE: return "APPLICATION_ACTIVITY_TYPE";
1188            case HOME_ACTIVITY_TYPE: return "HOME_ACTIVITY_TYPE";
1189            case RECENTS_ACTIVITY_TYPE: return "RECENTS_ACTIVITY_TYPE";
1190            default: return Integer.toString(type);
1191        }
1192    }
1193
1194    @Override
1195    public String toString() {
1196        if (stringName != null) {
1197            return stringName + " t" + (task == null ? -1 : task.taskId) +
1198                    (finishing ? " f}" : "}");
1199        }
1200        StringBuilder sb = new StringBuilder(128);
1201        sb.append("ActivityRecord{");
1202        sb.append(Integer.toHexString(System.identityHashCode(this)));
1203        sb.append(" u");
1204        sb.append(userId);
1205        sb.append(' ');
1206        sb.append(intent.getComponent().flattenToShortString());
1207        stringName = sb.toString();
1208        return toString();
1209    }
1210}
1211