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