diff options
Diffstat (limited to 'services/core/java/com/android/server/am/ActivityRecord.java')
-rw-r--r-- | services/core/java/com/android/server/am/ActivityRecord.java | 1068 |
1 files changed, 1068 insertions, 0 deletions
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java new file mode 100644 index 0000000..38b01df --- /dev/null +++ b/services/core/java/com/android/server/am/ActivityRecord.java @@ -0,0 +1,1068 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.am; + +import android.os.Trace; +import com.android.internal.R.styleable; +import com.android.internal.app.ResolverActivity; +import com.android.server.AttributeCache; +import com.android.server.am.ActivityStack.ActivityState; +import com.android.server.am.ActivityStackSupervisor.ActivityContainer; + +import android.app.ActivityOptions; +import android.app.ResultInfo; +import android.content.ComponentName; +import android.content.Intent; +import android.content.pm.ActivityInfo; +import android.content.pm.ApplicationInfo; +import android.content.res.CompatibilityInfo; +import android.content.res.Configuration; +import android.graphics.Bitmap; +import android.graphics.Rect; +import android.os.Build; +import android.os.Bundle; +import android.os.IBinder; +import android.os.Message; +import android.os.Process; +import android.os.RemoteException; +import android.os.SystemClock; +import android.os.UserHandle; +import android.util.EventLog; +import android.util.Log; +import android.util.Slog; +import android.util.TimeUtils; +import android.view.IApplicationToken; +import android.view.WindowManager; + +import java.io.PrintWriter; +import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.HashSet; + +/** + * An entry in the history stack, representing an activity. + */ +final class ActivityRecord { + static final String TAG = ActivityManagerService.TAG; + static final boolean DEBUG_SAVED_STATE = ActivityStackSupervisor.DEBUG_SAVED_STATE; + final public static String RECENTS_PACKAGE_NAME = "com.android.systemui.recent"; + + final ActivityManagerService service; // owner + final IApplicationToken.Stub appToken; // window manager token + final ActivityInfo info; // all about me + final int launchedFromUid; // always the uid who started the activity. + final String launchedFromPackage; // always the package who started the activity. + final int userId; // Which user is this running for? + final Intent intent; // the original intent that generated us + final ComponentName realActivity; // the intent component, or target of an alias. + final String shortComponentName; // the short component name of the intent + final String resolvedType; // as per original caller; + final String packageName; // the package implementing intent's component + final String processName; // process where this component wants to run + final String taskAffinity; // as per ActivityInfo.taskAffinity + final boolean stateNotNeeded; // As per ActivityInfo.flags + boolean fullscreen; // covers the full screen? + final boolean noDisplay; // activity is not displayed? + final boolean componentSpecified; // did caller specifiy an explicit component? + + static final int APPLICATION_ACTIVITY_TYPE = 0; + static final int HOME_ACTIVITY_TYPE = 1; + static final int RECENTS_ACTIVITY_TYPE = 2; + int mActivityType; + + final String baseDir; // where activity source (resources etc) located + final String resDir; // where public activity source (public resources etc) located + final String dataDir; // where activity data should go + CharSequence nonLocalizedLabel; // the label information from the package mgr. + int labelRes; // the label information from the package mgr. + int icon; // resource identifier of activity's icon. + int logo; // resource identifier of activity's logo. + int theme; // resource identifier of activity's theme. + int realTheme; // actual theme resource we will use, never 0. + int windowFlags; // custom window flags for preview window. + TaskRecord task; // the task this is in. + ThumbnailHolder thumbHolder; // where our thumbnails should go. + long displayStartTime; // when we started launching this activity + long fullyDrawnStartTime; // when we started launching this activity + long startTime; // last time this activity was started + long lastVisibleTime; // last time this activity became visible + long cpuTimeAtResume; // the cpu time of host process at the time of resuming activity + long pauseTime; // last time we started pausing the activity + long launchTickTime; // base time for launch tick messages + Configuration configuration; // configuration activity was last running in + CompatibilityInfo compat;// last used compatibility mode + ActivityRecord resultTo; // who started this entry, so will get our reply + final String resultWho; // additional identifier for use by resultTo. + final int requestCode; // code given by requester (resultTo) + ArrayList<ResultInfo> results; // pending ActivityResult objs we have received + HashSet<WeakReference<PendingIntentRecord>> pendingResults; // all pending intents for this act + ArrayList<Intent> newIntents; // any pending new intents for single-top mode + ActivityOptions pendingOptions; // most recently given options + HashSet<ConnectionRecord> connections; // All ConnectionRecord we hold + UriPermissionOwner uriPermissions; // current special URI access perms. + ProcessRecord app; // if non-null, hosting application + ActivityState state; // current state we are in + Bundle icicle; // last saved activity state + boolean frontOfTask; // is this the root activity of its task? + boolean launchFailed; // set if a launched failed, to abort on 2nd try + boolean haveState; // have we gotten the last activity state? + boolean stopped; // is activity pause finished? + boolean delayedResume; // not yet resumed because of stopped app switches? + boolean finishing; // activity in pending finish list? + boolean configDestroy; // need to destroy due to config change? + int configChangeFlags; // which config values have changed + boolean keysPaused; // has key dispatching been paused for it? + int launchMode; // the launch mode activity attribute. + boolean visible; // does this activity's window need to be shown? + boolean sleeping; // have we told the activity to sleep? + boolean waitingVisible; // true if waiting for a new act to become vis + boolean nowVisible; // is this activity's window visible? + boolean thumbnailNeeded;// has someone requested a thumbnail? + boolean idle; // has the activity gone idle? + boolean hasBeenLaunched;// has this activity ever been launched? + boolean frozenBeforeDestroy;// has been frozen but not yet destroyed. + boolean immersive; // immersive mode (don't interrupt if possible) + boolean forceNewConfig; // force re-create with new config next time + int launchCount; // count of launches since last state + long lastLaunchTime; // time of last lauch of this activity + ArrayList<ActivityStack> mChildContainers = new ArrayList<ActivityStack>(); + + String stringName; // for caching of toString(). + + private boolean inHistory; // are we in the history stack? + final ActivityStackSupervisor mStackSupervisor; + + void dump(PrintWriter pw, String prefix) { + final long now = SystemClock.uptimeMillis(); + pw.print(prefix); pw.print("packageName="); pw.print(packageName); + pw.print(" processName="); pw.println(processName); + pw.print(prefix); pw.print("launchedFromUid="); pw.print(launchedFromUid); + pw.print(" launchedFromPackage="); pw.print(launchedFromPackage); + pw.print(" userId="); pw.println(userId); + pw.print(prefix); pw.print("app="); pw.println(app); + pw.print(prefix); pw.println(intent.toInsecureStringWithClip()); + pw.print(prefix); pw.print("frontOfTask="); pw.print(frontOfTask); + pw.print(" task="); pw.println(task); + pw.print(prefix); pw.print("taskAffinity="); pw.println(taskAffinity); + pw.print(prefix); pw.print("realActivity="); + pw.println(realActivity.flattenToShortString()); + pw.print(prefix); pw.print("baseDir="); pw.println(baseDir); + if (!resDir.equals(baseDir)) { + pw.print(prefix); pw.print("resDir="); pw.println(resDir); + } + pw.print(prefix); pw.print("dataDir="); pw.println(dataDir); + pw.print(prefix); pw.print("stateNotNeeded="); pw.print(stateNotNeeded); + pw.print(" componentSpecified="); pw.print(componentSpecified); + pw.print(" mActivityType="); pw.println(mActivityType); + pw.print(prefix); pw.print("compat="); pw.print(compat); + pw.print(" labelRes=0x"); pw.print(Integer.toHexString(labelRes)); + pw.print(" icon=0x"); pw.print(Integer.toHexString(icon)); + pw.print(" theme=0x"); pw.println(Integer.toHexString(theme)); + pw.print(prefix); pw.print("config="); pw.println(configuration); + if (resultTo != null || resultWho != null) { + pw.print(prefix); pw.print("resultTo="); pw.print(resultTo); + pw.print(" resultWho="); pw.print(resultWho); + pw.print(" resultCode="); pw.println(requestCode); + } + if (results != null) { + pw.print(prefix); pw.print("results="); pw.println(results); + } + if (pendingResults != null && pendingResults.size() > 0) { + pw.print(prefix); pw.println("Pending Results:"); + for (WeakReference<PendingIntentRecord> wpir : pendingResults) { + PendingIntentRecord pir = wpir != null ? wpir.get() : null; + pw.print(prefix); pw.print(" - "); + if (pir == null) { + pw.println("null"); + } else { + pw.println(pir); + pir.dump(pw, prefix + " "); + } + } + } + if (newIntents != null && newIntents.size() > 0) { + pw.print(prefix); pw.println("Pending New Intents:"); + for (int i=0; i<newIntents.size(); i++) { + Intent intent = newIntents.get(i); + pw.print(prefix); pw.print(" - "); + if (intent == null) { + pw.println("null"); + } else { + pw.println(intent.toShortString(false, true, false, true)); + } + } + } + if (pendingOptions != null) { + pw.print(prefix); pw.print("pendingOptions="); pw.println(pendingOptions); + } + if (uriPermissions != null) { + if (uriPermissions.readUriPermissions != null) { + pw.print(prefix); pw.print("readUriPermissions="); + pw.println(uriPermissions.readUriPermissions); + } + if (uriPermissions.writeUriPermissions != null) { + pw.print(prefix); pw.print("writeUriPermissions="); + pw.println(uriPermissions.writeUriPermissions); + } + } + pw.print(prefix); pw.print("launchFailed="); pw.print(launchFailed); + pw.print(" launchCount="); pw.print(launchCount); + pw.print(" lastLaunchTime="); + if (lastLaunchTime == 0) pw.print("0"); + else TimeUtils.formatDuration(lastLaunchTime, now, pw); + pw.println(); + pw.print(prefix); pw.print("haveState="); pw.print(haveState); + pw.print(" icicle="); pw.println(icicle); + pw.print(prefix); pw.print("state="); pw.print(state); + pw.print(" stopped="); pw.print(stopped); + pw.print(" delayedResume="); pw.print(delayedResume); + pw.print(" finishing="); pw.println(finishing); + pw.print(prefix); pw.print("keysPaused="); pw.print(keysPaused); + pw.print(" inHistory="); pw.print(inHistory); + pw.print(" visible="); pw.print(visible); + pw.print(" sleeping="); pw.print(sleeping); + pw.print(" idle="); pw.println(idle); + pw.print(prefix); pw.print("fullscreen="); pw.print(fullscreen); + pw.print(" noDisplay="); pw.print(noDisplay); + pw.print(" immersive="); pw.print(immersive); + pw.print(" launchMode="); pw.println(launchMode); + pw.print(prefix); pw.print("frozenBeforeDestroy="); pw.print(frozenBeforeDestroy); + pw.print(" thumbnailNeeded="); pw.print(thumbnailNeeded); + pw.print(" forceNewConfig="); pw.println(forceNewConfig); + pw.print(prefix); pw.print("mActivityType="); + pw.println(activityTypeToString(mActivityType)); + pw.print(prefix); pw.print("thumbHolder: "); + pw.print(Integer.toHexString(System.identityHashCode(thumbHolder))); + if (thumbHolder != null) { + pw.print(" bm="); pw.print(thumbHolder.lastThumbnail); + pw.print(" desc="); pw.print(thumbHolder.lastDescription); + } + pw.println(); + if (displayStartTime != 0 || startTime != 0) { + pw.print(prefix); pw.print("displayStartTime="); + if (displayStartTime == 0) pw.print("0"); + else TimeUtils.formatDuration(displayStartTime, now, pw); + pw.print(" startTime="); + if (startTime == 0) pw.print("0"); + else TimeUtils.formatDuration(startTime, now, pw); + pw.println(); + } + if (lastVisibleTime != 0 || waitingVisible || nowVisible) { + pw.print(prefix); pw.print("waitingVisible="); pw.print(waitingVisible); + pw.print(" nowVisible="); pw.print(nowVisible); + pw.print(" lastVisibleTime="); + if (lastVisibleTime == 0) pw.print("0"); + else TimeUtils.formatDuration(lastVisibleTime, now, pw); + pw.println(); + } + if (configDestroy || configChangeFlags != 0) { + pw.print(prefix); pw.print("configDestroy="); pw.print(configDestroy); + pw.print(" configChangeFlags="); + pw.println(Integer.toHexString(configChangeFlags)); + } + if (connections != null) { + pw.print(prefix); pw.print("connections="); pw.println(connections); + } + } + + static class Token extends IApplicationToken.Stub { + final WeakReference<ActivityRecord> weakActivity; + + Token(ActivityRecord activity) { + weakActivity = new WeakReference<ActivityRecord>(activity); + } + + @Override public void windowsDrawn() { + ActivityRecord activity = weakActivity.get(); + if (activity != null) { + activity.windowsDrawn(); + } + } + + @Override public void windowsVisible() { + ActivityRecord activity = weakActivity.get(); + if (activity != null) { + activity.windowsVisible(); + } + } + + @Override public void windowsGone() { + ActivityRecord activity = weakActivity.get(); + if (activity != null) { + activity.windowsGone(); + } + } + + @Override public boolean keyDispatchingTimedOut(String reason) { + ActivityRecord activity = weakActivity.get(); + return activity != null && activity.keyDispatchingTimedOut(reason); + } + + @Override public long getKeyDispatchingTimeout() { + ActivityRecord activity = weakActivity.get(); + if (activity != null) { + return activity.getKeyDispatchingTimeout(); + } + return 0; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(128); + sb.append("Token{"); + sb.append(Integer.toHexString(System.identityHashCode(this))); + sb.append(' '); + sb.append(weakActivity.get()); + sb.append('}'); + return sb.toString(); + } + } + + static ActivityRecord forToken(IBinder token) { + try { + return token != null ? ((Token)token).weakActivity.get() : null; + } catch (ClassCastException e) { + Slog.w(ActivityManagerService.TAG, "Bad activity token: " + token, e); + return null; + } + } + + boolean isNotResolverActivity() { + return !ResolverActivity.class.getName().equals(realActivity.getClassName()); + } + + ActivityRecord(ActivityManagerService _service, ProcessRecord _caller, + int _launchedFromUid, String _launchedFromPackage, Intent _intent, String _resolvedType, + ActivityInfo aInfo, Configuration _configuration, + ActivityRecord _resultTo, String _resultWho, int _reqCode, + boolean _componentSpecified, ActivityStackSupervisor supervisor) { + service = _service; + appToken = new Token(this); + info = aInfo; + launchedFromUid = _launchedFromUid; + launchedFromPackage = _launchedFromPackage; + userId = UserHandle.getUserId(aInfo.applicationInfo.uid); + intent = _intent; + shortComponentName = _intent.getComponent().flattenToShortString(); + resolvedType = _resolvedType; + componentSpecified = _componentSpecified; + configuration = _configuration; + resultTo = _resultTo; + resultWho = _resultWho; + requestCode = _reqCode; + state = ActivityState.INITIALIZING; + frontOfTask = false; + launchFailed = false; + stopped = false; + delayedResume = false; + finishing = false; + configDestroy = false; + keysPaused = false; + inHistory = false; + visible = true; + waitingVisible = false; + nowVisible = false; + thumbnailNeeded = false; + idle = false; + hasBeenLaunched = false; + mStackSupervisor = supervisor; + + // This starts out true, since the initial state of an activity + // is that we have everything, and we shouldn't never consider it + // lacking in state to be removed if it dies. + haveState = true; + + if (aInfo != null) { + if (aInfo.targetActivity == null + || aInfo.launchMode == ActivityInfo.LAUNCH_MULTIPLE + || aInfo.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP) { + realActivity = _intent.getComponent(); + } else { + realActivity = new ComponentName(aInfo.packageName, + aInfo.targetActivity); + } + taskAffinity = aInfo.taskAffinity; + stateNotNeeded = (aInfo.flags& + ActivityInfo.FLAG_STATE_NOT_NEEDED) != 0; + baseDir = aInfo.applicationInfo.sourceDir; + resDir = aInfo.applicationInfo.publicSourceDir; + dataDir = aInfo.applicationInfo.dataDir; + nonLocalizedLabel = aInfo.nonLocalizedLabel; + labelRes = aInfo.labelRes; + if (nonLocalizedLabel == null && labelRes == 0) { + ApplicationInfo app = aInfo.applicationInfo; + nonLocalizedLabel = app.nonLocalizedLabel; + labelRes = app.labelRes; + } + icon = aInfo.getIconResource(); + logo = aInfo.getLogoResource(); + theme = aInfo.getThemeResource(); + realTheme = theme; + if (realTheme == 0) { + realTheme = aInfo.applicationInfo.targetSdkVersion + < Build.VERSION_CODES.HONEYCOMB + ? android.R.style.Theme + : android.R.style.Theme_Holo; + } + if ((aInfo.flags&ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0) { + windowFlags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED; + } + if ((aInfo.flags&ActivityInfo.FLAG_MULTIPROCESS) != 0 + && _caller != null + && (aInfo.applicationInfo.uid == Process.SYSTEM_UID + || aInfo.applicationInfo.uid == _caller.info.uid)) { + processName = _caller.processName; + } else { + processName = aInfo.processName; + } + + if (intent != null && (aInfo.flags & ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS) != 0) { + intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); + } + + packageName = aInfo.applicationInfo.packageName; + launchMode = aInfo.launchMode; + + AttributeCache.Entry ent = AttributeCache.instance().get(packageName, + realTheme, com.android.internal.R.styleable.Window, userId); + fullscreen = ent != null && !ent.array.getBoolean( + com.android.internal.R.styleable.Window_windowIsFloating, false) + && !ent.array.getBoolean( + com.android.internal.R.styleable.Window_windowIsTranslucent, false); + noDisplay = ent != null && ent.array.getBoolean( + com.android.internal.R.styleable.Window_windowNoDisplay, false); + + if ((!_componentSpecified || _launchedFromUid == Process.myUid() + || _launchedFromUid == 0) && + Intent.ACTION_MAIN.equals(_intent.getAction()) && + _intent.hasCategory(Intent.CATEGORY_HOME) && + _intent.getCategories().size() == 1 && + _intent.getData() == null && + _intent.getType() == null && + (intent.getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 && + isNotResolverActivity()) { + // This sure looks like a home activity! + mActivityType = HOME_ACTIVITY_TYPE; + } else if (realActivity.getClassName().contains(RECENTS_PACKAGE_NAME)) { + mActivityType = RECENTS_ACTIVITY_TYPE; + } else { + mActivityType = APPLICATION_ACTIVITY_TYPE; + } + + immersive = (aInfo.flags & ActivityInfo.FLAG_IMMERSIVE) != 0; + } else { + realActivity = null; + taskAffinity = null; + stateNotNeeded = false; + baseDir = null; + resDir = null; + dataDir = null; + processName = null; + packageName = null; + fullscreen = true; + noDisplay = false; + mActivityType = APPLICATION_ACTIVITY_TYPE; + immersive = false; + } + } + + void setTask(TaskRecord newTask, ThumbnailHolder newThumbHolder, boolean isRoot) { + if (task != null && task.removeActivity(this)) { + if (task != newTask) { + mStackSupervisor.removeTask(task); + } else { + Slog.d(TAG, "!!! REMOVE THIS LOG !!! setTask: nearly removed stack=" + + (newTask == null ? null : newTask.stack)); + } + } + if (inHistory && !finishing) { + if (task != null) { + task.numActivities--; + } + if (newTask != null) { + newTask.numActivities++; + } + } + if (newThumbHolder == null) { + newThumbHolder = newTask; + } + task = newTask; + if (!isRoot && (intent.getFlags()&Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) { + // This is the start of a new sub-task. + if (thumbHolder == null) { + thumbHolder = new ThumbnailHolder(); + } + } else { + thumbHolder = newThumbHolder; + } + } + + boolean changeWindowTranslucency(boolean toOpaque) { + if (fullscreen == toOpaque) { + return false; + } + AttributeCache.Entry ent = + AttributeCache.instance().get(packageName, realTheme, styleable.Window, userId); + if (ent == null + || !ent.array.getBoolean(styleable.Window_windowIsTranslucent, false) + || ent.array.getBoolean(styleable.Window_windowIsFloating, false)) { + return false; + } + + // Keep track of the number of fullscreen activities in this task. + task.numFullscreen += toOpaque ? +1 : -1; + + fullscreen = toOpaque; + return true; + } + + void putInHistory() { + if (!inHistory) { + inHistory = true; + if (task != null && !finishing) { + task.numActivities++; + } + } + } + + void takeFromHistory() { + if (inHistory) { + inHistory = false; + if (task != null && !finishing) { + task.numActivities--; + task = null; + } + clearOptionsLocked(); + } + } + + boolean isInHistory() { + return inHistory; + } + + boolean isHomeActivity() { + return mActivityType == HOME_ACTIVITY_TYPE; + } + + boolean isRecentsActivity() { + return mActivityType == RECENTS_ACTIVITY_TYPE; + } + + boolean isApplicationActivity() { + return mActivityType == APPLICATION_ACTIVITY_TYPE; + } + + void makeFinishing() { + if (!finishing) { + finishing = true; + if (task != null && inHistory) { + task.numActivities--; + } + if (stopped) { + clearOptionsLocked(); + } + } + } + + boolean isRootActivity() { + final ArrayList<ActivityRecord> activities = task.mActivities; + return activities.size() == 0 || this == activities.get(0); + } + + UriPermissionOwner getUriPermissionsLocked() { + if (uriPermissions == null) { + uriPermissions = new UriPermissionOwner(service, this); + } + return uriPermissions; + } + + void addResultLocked(ActivityRecord from, String resultWho, + int requestCode, int resultCode, + Intent resultData) { + ActivityResult r = new ActivityResult(from, resultWho, + requestCode, resultCode, resultData); + if (results == null) { + results = new ArrayList<ResultInfo>(); + } + results.add(r); + } + + void removeResultsLocked(ActivityRecord from, String resultWho, + int requestCode) { + if (results != null) { + for (int i=results.size()-1; i>=0; i--) { + ActivityResult r = (ActivityResult)results.get(i); + if (r.mFrom != from) continue; + if (r.mResultWho == null) { + if (resultWho != null) continue; + } else { + if (!r.mResultWho.equals(resultWho)) continue; + } + if (r.mRequestCode != requestCode) continue; + + results.remove(i); + } + } + } + + void addNewIntentLocked(Intent intent) { + if (newIntents == null) { + newIntents = new ArrayList<Intent>(); + } + newIntents.add(intent); + } + + /** + * Deliver a new Intent to an existing activity, so that its onNewIntent() + * method will be called at the proper time. + */ + final void deliverNewIntentLocked(int callingUid, Intent intent) { + // The activity now gets access to the data associated with this Intent. + service.grantUriPermissionFromIntentLocked(callingUid, packageName, + intent, getUriPermissionsLocked()); + // We want to immediately deliver the intent to the activity if + // it is currently the top resumed activity... however, if the + // device is sleeping, then all activities are stopped, so in that + // case we will deliver it if this is the current top activity on its + // stack. + boolean unsent = true; + if ((state == ActivityState.RESUMED || (service.mSleeping + && task.stack.topRunningActivityLocked(null) == this)) + && app != null && app.thread != null) { + try { + ArrayList<Intent> ar = new ArrayList<Intent>(); + intent = new Intent(intent); + ar.add(intent); + app.thread.scheduleNewIntent(ar, appToken); + unsent = false; + } catch (RemoteException e) { + Slog.w(ActivityManagerService.TAG, + "Exception thrown sending new intent to " + this, e); + } catch (NullPointerException e) { + Slog.w(ActivityManagerService.TAG, + "Exception thrown sending new intent to " + this, e); + } + } + if (unsent) { + addNewIntentLocked(new Intent(intent)); + } + } + + void updateOptionsLocked(Bundle options) { + if (options != null) { + if (pendingOptions != null) { + pendingOptions.abort(); + } + pendingOptions = new ActivityOptions(options); + } + } + + void updateOptionsLocked(ActivityOptions options) { + if (options != null) { + if (pendingOptions != null) { + pendingOptions.abort(); + } + pendingOptions = options; + } + } + + void applyOptionsLocked() { + if (pendingOptions != null) { + final int animationType = pendingOptions.getAnimationType(); + switch (animationType) { + case ActivityOptions.ANIM_CUSTOM: + service.mWindowManager.overridePendingAppTransition( + pendingOptions.getPackageName(), + pendingOptions.getCustomEnterResId(), + pendingOptions.getCustomExitResId(), + pendingOptions.getOnAnimationStartListener()); + break; + case ActivityOptions.ANIM_SCALE_UP: + service.mWindowManager.overridePendingAppTransitionScaleUp( + pendingOptions.getStartX(), pendingOptions.getStartY(), + pendingOptions.getStartWidth(), pendingOptions.getStartHeight()); + if (intent.getSourceBounds() == null) { + intent.setSourceBounds(new Rect(pendingOptions.getStartX(), + pendingOptions.getStartY(), + pendingOptions.getStartX()+pendingOptions.getStartWidth(), + pendingOptions.getStartY()+pendingOptions.getStartHeight())); + } + break; + case ActivityOptions.ANIM_THUMBNAIL_SCALE_UP: + case ActivityOptions.ANIM_THUMBNAIL_SCALE_DOWN: + boolean scaleUp = (animationType == ActivityOptions.ANIM_THUMBNAIL_SCALE_UP); + service.mWindowManager.overridePendingAppTransitionThumb( + pendingOptions.getThumbnail(), + pendingOptions.getStartX(), pendingOptions.getStartY(), + pendingOptions.getOnAnimationStartListener(), + scaleUp); + if (intent.getSourceBounds() == null) { + intent.setSourceBounds(new Rect(pendingOptions.getStartX(), + pendingOptions.getStartY(), + pendingOptions.getStartX() + + pendingOptions.getThumbnail().getWidth(), + pendingOptions.getStartY() + + pendingOptions.getThumbnail().getHeight())); + } + break; + } + pendingOptions = null; + } + } + + void clearOptionsLocked() { + if (pendingOptions != null) { + pendingOptions.abort(); + pendingOptions = null; + } + } + + ActivityOptions takeOptionsLocked() { + ActivityOptions opts = pendingOptions; + pendingOptions = null; + return opts; + } + + void removeUriPermissionsLocked() { + if (uriPermissions != null) { + uriPermissions.removeUriPermissionsLocked(); + uriPermissions = null; + } + } + + void pauseKeyDispatchingLocked() { + if (!keysPaused) { + keysPaused = true; + service.mWindowManager.pauseKeyDispatching(appToken); + } + } + + void resumeKeyDispatchingLocked() { + if (keysPaused) { + keysPaused = false; + service.mWindowManager.resumeKeyDispatching(appToken); + } + } + + void updateThumbnail(Bitmap newThumbnail, CharSequence description) { + if (thumbHolder != null) { + if (newThumbnail != null) { + if (ActivityManagerService.DEBUG_THUMBNAILS) Slog.i(ActivityManagerService.TAG, + "Setting thumbnail of " + this + " holder " + thumbHolder + + " to " + newThumbnail); + thumbHolder.lastThumbnail = newThumbnail; + } + thumbHolder.lastDescription = description; + } + } + + void startLaunchTickingLocked() { + if (ActivityManagerService.IS_USER_BUILD) { + return; + } + if (launchTickTime == 0) { + launchTickTime = SystemClock.uptimeMillis(); + continueLaunchTickingLocked(); + } + } + + boolean continueLaunchTickingLocked() { + if (launchTickTime != 0) { + final ActivityStack stack = task.stack; + Message msg = stack.mHandler.obtainMessage(ActivityStack.LAUNCH_TICK_MSG, this); + stack.mHandler.removeMessages(ActivityStack.LAUNCH_TICK_MSG); + stack.mHandler.sendMessageDelayed(msg, ActivityStack.LAUNCH_TICK); + return true; + } + return false; + } + + void finishLaunchTickingLocked() { + launchTickTime = 0; + task.stack.mHandler.removeMessages(ActivityStack.LAUNCH_TICK_MSG); + } + + // IApplicationToken + + public boolean mayFreezeScreenLocked(ProcessRecord app) { + // Only freeze the screen if this activity is currently attached to + // an application, and that application is not blocked or unresponding. + // In any other case, we can't count on getting the screen unfrozen, + // so it is best to leave as-is. + return app != null && !app.crashing && !app.notResponding; + } + + public void startFreezingScreenLocked(ProcessRecord app, int configChanges) { + if (mayFreezeScreenLocked(app)) { + service.mWindowManager.startAppFreezingScreen(appToken, configChanges); + } + } + + public void stopFreezingScreenLocked(boolean force) { + if (force || frozenBeforeDestroy) { + frozenBeforeDestroy = false; + service.mWindowManager.stopAppFreezingScreen(appToken, force); + } + } + + public void reportFullyDrawnLocked() { + final long curTime = SystemClock.uptimeMillis(); + if (displayStartTime != 0) { + reportLaunchTimeLocked(curTime); + } + if (fullyDrawnStartTime != 0) { + final ActivityStack stack = task.stack; + final long thisTime = curTime - fullyDrawnStartTime; + final long totalTime = stack.mFullyDrawnStartTime != 0 + ? (curTime - stack.mFullyDrawnStartTime) : thisTime; + if (ActivityManagerService.SHOW_ACTIVITY_START_TIME) { + Trace.asyncTraceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER, "drawing", 0); + EventLog.writeEvent(EventLogTags.AM_ACTIVITY_FULLY_DRAWN_TIME, + userId, System.identityHashCode(this), shortComponentName, + thisTime, totalTime); + StringBuilder sb = service.mStringBuilder; + sb.setLength(0); + sb.append("Fully drawn "); + sb.append(shortComponentName); + sb.append(": "); + TimeUtils.formatDuration(thisTime, sb); + if (thisTime != totalTime) { + sb.append(" (total "); + TimeUtils.formatDuration(totalTime, sb); + sb.append(")"); + } + Log.i(ActivityManagerService.TAG, sb.toString()); + } + if (totalTime > 0) { + service.mUsageStatsService.noteFullyDrawnTime(realActivity, (int) totalTime); + } + fullyDrawnStartTime = 0; + stack.mFullyDrawnStartTime = 0; + } + } + + private void reportLaunchTimeLocked(final long curTime) { + final ActivityStack stack = task.stack; + final long thisTime = curTime - displayStartTime; + final long totalTime = stack.mLaunchStartTime != 0 + ? (curTime - stack.mLaunchStartTime) : thisTime; + if (ActivityManagerService.SHOW_ACTIVITY_START_TIME) { + Trace.asyncTraceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER, "launching", 0); + EventLog.writeEvent(EventLogTags.AM_ACTIVITY_LAUNCH_TIME, + userId, System.identityHashCode(this), shortComponentName, + thisTime, totalTime); + StringBuilder sb = service.mStringBuilder; + sb.setLength(0); + sb.append("Displayed "); + sb.append(shortComponentName); + sb.append(": "); + TimeUtils.formatDuration(thisTime, sb); + if (thisTime != totalTime) { + sb.append(" (total "); + TimeUtils.formatDuration(totalTime, sb); + sb.append(")"); + } + Log.i(ActivityManagerService.TAG, sb.toString()); + } + mStackSupervisor.reportActivityLaunchedLocked(false, this, thisTime, totalTime); + if (totalTime > 0) { + service.mUsageStatsService.noteLaunchTime(realActivity, (int)totalTime); + } + displayStartTime = 0; + stack.mLaunchStartTime = 0; + } + + public void windowsDrawn() { + synchronized(service) { + if (displayStartTime != 0) { + reportLaunchTimeLocked(SystemClock.uptimeMillis()); + } + startTime = 0; + finishLaunchTickingLocked(); + } + } + + public void windowsVisible() { + synchronized(service) { + mStackSupervisor.reportActivityVisibleLocked(this); + if (ActivityManagerService.DEBUG_SWITCH) Log.v( + ActivityManagerService.TAG, "windowsVisible(): " + this); + if (!nowVisible) { + nowVisible = true; + lastVisibleTime = SystemClock.uptimeMillis(); + if (!idle) { + // Instead of doing the full stop routine here, let's just + // hide any activities we now can, and let them stop when + // the normal idle happens. + mStackSupervisor.processStoppingActivitiesLocked(false); + } else { + // If this activity was already idle, then we now need to + // make sure we perform the full stop of any activities + // that are waiting to do so. This is because we won't + // do that while they are still waiting for this one to + // become visible. + final int N = mStackSupervisor.mWaitingVisibleActivities.size(); + if (N > 0) { + for (int i=0; i<N; i++) { + ActivityRecord r = mStackSupervisor.mWaitingVisibleActivities.get(i); + r.waitingVisible = false; + if (ActivityManagerService.DEBUG_SWITCH) Log.v( + ActivityManagerService.TAG, + "Was waiting for visible: " + r); + } + mStackSupervisor.mWaitingVisibleActivities.clear(); + mStackSupervisor.scheduleIdleLocked(); + } + } + service.scheduleAppGcsLocked(); + } + } + } + + public void windowsGone() { + if (ActivityManagerService.DEBUG_SWITCH) Log.v( + ActivityManagerService.TAG, "windowsGone(): " + this); + nowVisible = false; + } + + private ActivityRecord getWaitingHistoryRecordLocked() { + // First find the real culprit... if we are waiting + // for another app to start, then we have paused dispatching + // for this activity. + ActivityRecord r = this; + final ActivityStack stack = task.stack; + if (r.waitingVisible) { + // Hmmm, who might we be waiting for? + r = stack.mResumedActivity; + if (r == null) { + r = stack.mPausingActivity; + } + // Both of those null? Fall back to 'this' again + if (r == null) { + r = this; + } + } + + return r; + } + + public boolean keyDispatchingTimedOut(String reason) { + ActivityRecord r; + ProcessRecord anrApp; + synchronized(service) { + r = getWaitingHistoryRecordLocked(); + anrApp = r != null ? r.app : null; + } + return service.inputDispatchingTimedOut(anrApp, r, this, false, reason); + } + + /** Returns the key dispatching timeout for this application token. */ + public long getKeyDispatchingTimeout() { + synchronized(service) { + ActivityRecord r = getWaitingHistoryRecordLocked(); + return ActivityManagerService.getInputDispatchingTimeoutLocked(r); + } + } + + /** + * This method will return true if the activity is either visible, is becoming visible, is + * currently pausing, or is resumed. + */ + public boolean isInterestingToUserLocked() { + return visible || nowVisible || state == ActivityState.PAUSING || + state == ActivityState.RESUMED; + } + + public void setSleeping(boolean _sleeping) { + if (sleeping == _sleeping) { + return; + } + if (app != null && app.thread != null) { + try { + app.thread.scheduleSleeping(appToken, _sleeping); + if (_sleeping && !mStackSupervisor.mGoingToSleepActivities.contains(this)) { + mStackSupervisor.mGoingToSleepActivities.add(this); + } + sleeping = _sleeping; + } catch (RemoteException e) { + Slog.w(TAG, "Exception thrown when sleeping: " + intent.getComponent(), e); + } + } + } + + static void activityResumedLocked(IBinder token) { + final ActivityRecord r = ActivityRecord.forToken(token); + if (DEBUG_SAVED_STATE) Slog.i(TAG, "Resumed activity; dropping state of: " + r); + r.icicle = null; + r.haveState = false; + } + + static int getTaskForActivityLocked(IBinder token, boolean onlyRoot) { + final ActivityRecord r = ActivityRecord.forToken(token); + if (r == null) { + return -1; + } + final TaskRecord task = r.task; + switch (task.mActivities.indexOf(r)) { + case -1: return -1; + case 0: return task.taskId; + default: return onlyRoot ? -1 : task.taskId; + } + } + + static ActivityRecord isInStackLocked(IBinder token) { + final ActivityRecord r = ActivityRecord.forToken(token); + if (r != null) { + return r.task.stack.isInStackLocked(token); + } + return null; + } + + static ActivityStack getStackLocked(IBinder token) { + final ActivityRecord r = ActivityRecord.isInStackLocked(token); + if (r != null) { + return r.task.stack; + } + return null; + } + + private String activityTypeToString(int type) { + switch (type) { + case APPLICATION_ACTIVITY_TYPE: return "APPLICATION_ACTIVITY_TYPE"; + case HOME_ACTIVITY_TYPE: return "HOME_ACTIVITY_TYPE"; + case RECENTS_ACTIVITY_TYPE: return "RECENTS_ACTIVITY_TYPE"; + default: return Integer.toString(type); + } + } + + @Override + public String toString() { + if (stringName != null) { + return stringName + " t" + (task == null ? -1 : task.taskId) + + (finishing ? " f}" : "}"); + } + StringBuilder sb = new StringBuilder(128); + sb.append("ActivityRecord{"); + sb.append(Integer.toHexString(System.identityHashCode(this))); + sb.append(" u"); + sb.append(userId); + sb.append(' '); + sb.append(intent.getComponent().flattenToShortString()); + stringName = sb.toString(); + return toString(); + } +} |