Add AppWindowTokens to TaskList.
- Add/remove/move TaskLists from ActivityStack.
- Further isolate mHistory.
- Cleanup warnings by parameterizing ArrayList.
- Fix previous bugs.
Change-Id: Ife8c7b7347479c70f10467cc384283456149ac50
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index d969709..76836f9 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -24,11 +24,13 @@
import com.android.server.am.ActivityManagerService.ItemMatcher;
import com.android.server.am.ActivityManagerService.PendingActivityLaunch;
import com.android.server.wm.AppTransition;
+import com.android.server.wm.TaskGroup;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.ActivityOptions;
import android.app.AppGlobals;
+import android.app.IActivityController;
import android.app.IActivityManager;
import android.app.IThumbnailReceiver;
import android.app.IThumbnailRetriever;
@@ -501,14 +503,10 @@
return null;
}
- final int indexOfTokenLocked(IBinder token) {
+ private final int indexOfTokenLocked(IBinder token) {
return mHistory.indexOf(ActivityRecord.forToken(token));
}
- final int indexOfActivityLocked(ActivityRecord r) {
- return mHistory.indexOf(r);
- }
-
final ActivityRecord isInStackLocked(IBinder token) {
ActivityRecord r = ActivityRecord.forToken(token);
if (mHistory.contains(r)) {
@@ -517,14 +515,6 @@
return null;
}
- // TODO: This exposes mHistory too much, replace usage with ActivityStack methods.
- final ActivityRecord getActivityAtIndex(int index) {
- if (index >= 0 && index < mHistory.size()) {
- return mHistory.get(index);
- }
- return null;
- }
-
int getTaskForActivityLocked(IBinder token, boolean onlyRoot) {
TaskRecord lastTask = null;
final int N = mHistory.size();
@@ -745,7 +735,13 @@
try {
profileFd = profileFd.dup();
} catch (IOException e) {
- profileFd = null;
+ if (profileFd != null) {
+ try {
+ profileFd.close();
+ } catch (IOException o) {
+ }
+ profileFd = null;
+ }
}
}
app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
@@ -1758,7 +1754,7 @@
try {
// Deliver all pending results.
- ArrayList a = next.results;
+ ArrayList<ResultInfo> a = next.results;
if (a != null) {
final int N = a.size();
if (!next.finishing && N > 0) {
@@ -2156,6 +2152,7 @@
}
i++;
}
+ mService.mWindowManager.moveTaskToBottom(target.task.taskId);
if (taskTop == p) {
taskTop = below;
}
@@ -2304,6 +2301,8 @@
validateAppTokensLocked();
}
}
+ // TODO: This is wrong because it doesn't take lastReparentPos into account.
+ mService.mWindowManager.moveTaskToTop(task.taskId);
replyChainEnd = -1;
// Now we've moved it in to place... but what if this is
@@ -2413,7 +2412,7 @@
if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE
&& (launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) == 0) {
if (!ret.finishing) {
- int index = indexOfTokenLocked(ret.appToken);
+ int index = mHistory.indexOf(ret);
if (index >= 0) {
finishActivityLocked(ret, index, Activity.RESULT_CANCELED,
null, "clear", false);
@@ -3568,7 +3567,7 @@
}
// Get the activity record.
- int index = indexOfActivityLocked(r);
+ int index = mHistory.indexOf(r);
if (index >= 0) {
res = r;
@@ -3654,7 +3653,7 @@
// Stop any activities that are scheduled to do so but have been
// waiting for the next one to start.
for (i=0; i<NS; i++) {
- ActivityRecord r = (ActivityRecord)stops.get(i);
+ ActivityRecord r = stops.get(i);
synchronized (mService) {
if (r.finishing) {
finishCurrentActivityLocked(r, FINISH_IMMEDIATELY, false);
@@ -3667,7 +3666,7 @@
// Finish any activities that are scheduled to do so but have been
// waiting for the next one to start.
for (i=0; i<NF; i++) {
- ActivityRecord r = (ActivityRecord)finishes.get(i);
+ ActivityRecord r = finishes.get(i);
synchronized (mService) {
activityRemoved = destroyActivityLocked(r, true, false, "finish-idle");
}
@@ -3675,7 +3674,7 @@
// Report back to any thumbnail receivers.
for (i=0; i<NT; i++) {
- ActivityRecord r = (ActivityRecord)thumbnails.get(i);
+ ActivityRecord r = thumbnails.get(i);
mService.sendPendingThumbnail(r, null, null, null, true);
}
@@ -3730,7 +3729,7 @@
int i;
for (i=mHistory.size()-1; i>=0; i--) {
- ActivityRecord r = (ActivityRecord)mHistory.get(i);
+ ActivityRecord r = mHistory.get(i);
if (r.resultTo == self && r.requestCode == requestCode) {
if ((r.resultWho == null && resultWho == null) ||
(r.resultWho != null && r.resultWho.equals(resultWho))) {
@@ -3742,6 +3741,36 @@
mService.updateOomAdjLocked();
}
+ final void finishTopRunningActivityLocked(ProcessRecord app) {
+ ActivityRecord r = topRunningActivityLocked(null);
+ if (r != null && r.app == app) {
+ // If the top running activity is from this crashing
+ // process, then terminate it to avoid getting in a loop.
+ Slog.w(TAG, " Force finishing activity "
+ + r.intent.getComponent().flattenToShortString());
+ int index = mHistory.indexOf(r);
+ r.stack.finishActivityLocked(r, index,
+ Activity.RESULT_CANCELED, null, "crashed", false);
+ // Also terminate any activities below it that aren't yet
+ // stopped, to avoid a situation where one will get
+ // re-start our crashing activity once it gets resumed again.
+ index--;
+ if (index >= 0) {
+ r = mHistory.get(index);
+ if (r.state == ActivityState.RESUMED
+ || r.state == ActivityState.PAUSING
+ || r.state == ActivityState.PAUSED) {
+ if (!r.isHomeActivity || mService.mHomeProcess != r.app) {
+ Slog.w(TAG, " Force finishing activity "
+ + r.intent.getComponent().flattenToShortString());
+ r.stack.finishActivityLocked(r, index,
+ Activity.RESULT_CANCELED, null, "crashed", false);
+ }
+ }
+ }
+ }
+ }
+
final boolean finishActivityAffinityLocked(IBinder token) {
int index = indexOfTokenLocked(token);
if (DEBUG_RESULTS) Slog.v(
@@ -3800,6 +3829,19 @@
* @return Returns true if this activity has been removed from the history
* list, or false if it is still in the list and will be removed later.
*/
+ final boolean finishActivityLocked(ActivityRecord r,
+ int resultCode, Intent resultData, String reason, boolean oomAdj) {
+ int index = mHistory.indexOf(r);
+ if (index >= 0) {
+ return finishActivityLocked(r, index, resultCode, resultData, reason, false, oomAdj);
+ }
+ return false;
+ }
+
+ /**
+ * @return Returns true if this activity has been removed from the history
+ * list, or false if it is still in the list and will be removed later.
+ */
final boolean finishActivityLocked(ActivityRecord r, int index,
int resultCode, Intent resultData, String reason, boolean oomAdj) {
return finishActivityLocked(r, index, resultCode, resultData, reason, false, oomAdj);
@@ -3892,7 +3934,7 @@
private final ActivityRecord finishCurrentActivityLocked(ActivityRecord r,
int mode, boolean oomAdj) {
- final int index = indexOfActivityLocked(r);
+ final int index = mHistory.indexOf(r);
if (index < 0) {
return null;
}
@@ -3948,16 +3990,102 @@
resumeTopActivityLocked(null);
}
return activityRemoved ? null : r;
- } else {
- // Need to go through the full pause cycle to get this
- // activity into the stopped state and then finish it.
- if (localLOGV) Slog.v(TAG, "Enqueueing pending finish: " + r);
- mFinishingActivities.add(r);
- resumeTopActivityLocked(null);
}
+
+ // Need to go through the full pause cycle to get this
+ // activity into the stopped state and then finish it.
+ if (localLOGV) Slog.v(TAG, "Enqueueing pending finish: " + r);
+ mFinishingActivities.add(r);
+ resumeTopActivityLocked(null);
return r;
}
+ final boolean navigateUpToLocked(ActivityRecord srec, Intent destIntent, int resultCode,
+ Intent resultData) {
+ final int start = mHistory.indexOf(srec);
+ if (start < 0) {
+ // Current activity is not in history stack; do nothing.
+ return false;
+ }
+ int finishTo = start - 1;
+ ActivityRecord parent = null;
+ boolean foundParentInTask = false;
+ ComponentName dest = destIntent.getComponent();
+ if (dest != null) {
+ TaskRecord tr = srec.task;
+ for (int i = start - 1; i >= 0; i--) {
+ ActivityRecord r = mHistory.get(i);
+ if (tr != r.task) {
+ // Couldn't find parent in the same task; stop at the one above this.
+ // (Root of current task; in-app "home" behavior)
+ // Always at least finish the current activity.
+ finishTo = Math.min(start - 1, i + 1);
+ parent = mHistory.get(finishTo);
+ break;
+ } else if (r.info.packageName.equals(dest.getPackageName()) &&
+ r.info.name.equals(dest.getClassName())) {
+ finishTo = i;
+ parent = r;
+ foundParentInTask = true;
+ break;
+ }
+ }
+ }
+
+ IActivityController controller = mService.mController;
+ if (controller != null) {
+ ActivityRecord next = topRunningActivityLocked(srec.appToken, 0);
+ if (next != null) {
+ // ask watcher if this is allowed
+ boolean resumeOK = true;
+ try {
+ resumeOK = controller.activityResuming(next.packageName);
+ } catch (RemoteException e) {
+ mService.mController = null;
+ }
+
+ if (!resumeOK) {
+ return false;
+ }
+ }
+ }
+ final long origId = Binder.clearCallingIdentity();
+ for (int i = start; i > finishTo; i--) {
+ ActivityRecord r = mHistory.get(i);
+ requestFinishActivityLocked(r.appToken, resultCode, resultData,
+ "navigate-up", true);
+ // Only return the supplied result for the first activity finished
+ resultCode = Activity.RESULT_CANCELED;
+ resultData = null;
+ }
+
+ if (parent != null && foundParentInTask) {
+ final int parentLaunchMode = parent.info.launchMode;
+ final int destIntentFlags = destIntent.getFlags();
+ if (parentLaunchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE ||
+ parentLaunchMode == ActivityInfo.LAUNCH_SINGLE_TASK ||
+ parentLaunchMode == ActivityInfo.LAUNCH_SINGLE_TOP ||
+ (destIntentFlags & Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
+ parent.deliverNewIntentLocked(srec.info.applicationInfo.uid, destIntent);
+ } else {
+ try {
+ ActivityInfo aInfo = AppGlobals.getPackageManager().getActivityInfo(
+ destIntent.getComponent(), 0, srec.userId);
+ int res = startActivityLocked(srec.app.thread, destIntent,
+ null, aInfo, parent.appToken, null,
+ 0, -1, parent.launchedFromUid, parent.launchedFromPackage,
+ 0, null, true, null);
+ foundParentInTask = res == ActivityManager.START_SUCCESS;
+ } catch (RemoteException e) {
+ foundParentInTask = false;
+ }
+ requestFinishActivityLocked(parent.appToken, resultCode,
+ resultData, "navigate-up", true);
+ }
+ }
+ Binder.restoreCallingIdentity(origId);
+ return foundParentInTask;
+ }
/**
* Perform the common clean-up of an activity record. This is called both
* as part of destroyActivityLocked() (when destroying the client-side
@@ -4216,7 +4344,7 @@
mHandler.removeMessages(DESTROY_TIMEOUT_MSG, r);
}
- int index = indexOfActivityLocked(r);
+ int index = mHistory.indexOf(r);
if (index >= 0) {
if (r.state == ActivityState.DESTROYING) {
cleanUpActivityLocked(r, true, false);
@@ -4230,15 +4358,15 @@
}
}
- private void removeHistoryRecordsForAppLocked(ArrayList list, ProcessRecord app,
- String listName) {
+ private void removeHistoryRecordsForAppLocked(ArrayList<ActivityRecord> list,
+ ProcessRecord app, String listName) {
int i = list.size();
if (DEBUG_CLEANUP) Slog.v(
TAG, "Removing app " + app + " from list " + listName
+ " with " + i + " entries");
while (i > 0) {
i--;
- ActivityRecord r = (ActivityRecord)list.get(i);
+ ActivityRecord r = list.get(i);
if (DEBUG_CLEANUP) Slog.v(TAG, "Record #" + i + " " + r);
if (r.app == app) {
if (DEBUG_CLEANUP) Slog.v(TAG, "---> REMOVING this entry!");
@@ -4264,7 +4392,7 @@
TAG, "Removing app " + app + " from history with " + i + " entries");
while (i > 0) {
i--;
- ActivityRecord r = (ActivityRecord)mHistory.get(i);
+ ActivityRecord r = mHistory.get(i);
if (DEBUG_CLEANUP) Slog.v(
TAG, "Record #" + i + " " + r + ": app=" + r.app);
if (r.app == app) {
@@ -4440,6 +4568,7 @@
if (VALIDATE_TOKENS) {
validateAppTokensLocked();
}
+ mService.mWindowManager.moveTaskToTop(task);
finishTaskMoveLocked(task);
EventLog.writeEvent(EventLogTags.AM_TASK_TO_FRONT, tr.userId, task);
@@ -4532,6 +4661,7 @@
if (VALIDATE_TOKENS) {
validateAppTokensLocked();
}
+ mService.mWindowManager.moveTaskToBottom(task);
finishTaskMoveLocked(task);
return true;
@@ -4561,9 +4691,8 @@
TaskAccessInfo info = getTaskAccessInfoLocked(tr.taskId, true);
if (info.numSubThumbbails <= 0) {
return info.mainThumbnail != null ? info.mainThumbnail : tr.lastThumbnail;
- } else {
- return info.subtasks.get(info.numSubThumbbails-1).holder.lastThumbnail;
}
+ return info.subtasks.get(info.numSubThumbbails-1).holder.lastThumbnail;
}
public ActivityRecord removeTaskActivitiesLocked(int taskId, int subTaskIndex,
@@ -4643,6 +4772,7 @@
}
if (thumbs.numSubThumbbails > 0) {
thumbs.retriever = new IThumbnailRetriever.Stub() {
+ @Override
public Bitmap getThumbnail(int index) {
if (index < 0 || index >= thumbs.subtasks.size()) {
return null;