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