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