Skip to content

Commit be70785

Browse files
author
Dianne Hackborn
committed
Make activity manager more robust in the face of app activity leaks.
This came up from bug #5601885: Memory increase (leak?) in system_server Stingray MR1 This isn't *really* a leak in the system process -- it is a leak in an application process that is causing the system process to keep around a bunch of ActivityRecord objects longer than it should, until that app process is ultimately killed. Unfortunately these days leaking an ActivityRecord also often means leaking a thumbnail, which is a big slab of memory. So make the activity manager better about this, using a weak reference from the handle the object has so we can still clean away most of the state associated with the ActivityRecord even if the client side leaks its own reference. Change-Id: Idbab45e09749cdfb54899203da7981e7b3576e25
1 parent 24597eb commit be70785

File tree

4 files changed

+198
-119
lines changed

4 files changed

+198
-119
lines changed

services/java/com/android/server/am/ActivityManagerService.java

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1669,7 +1669,7 @@ private HashMap<String, IBinder> getCommonServicesLocked() {
16691669
final void setFocusedActivityLocked(ActivityRecord r) {
16701670
if (mFocusedActivity != r) {
16711671
mFocusedActivity = r;
1672-
mWindowManager.setFocusedApp(r, true);
1672+
mWindowManager.setFocusedApp(r.appToken, true);
16731673
}
16741674
}
16751675

@@ -2346,7 +2346,8 @@ public boolean startNextMatchingActivity(IBinder callingActivity,
23462346
// XXX we are not dealing with propagating grantedUriPermissions...
23472347
// those are not yet exposed to user code, so there is no need.
23482348
int res = mMainStack.startActivityLocked(r.app.thread, intent,
2349-
r.resolvedType, null, 0, aInfo, resultTo, resultWho,
2349+
r.resolvedType, null, 0, aInfo,
2350+
resultTo != null ? resultTo.appToken : null, resultWho,
23502351
requestCode, -1, r.launchedFromUid, false, false, null);
23512352
Binder.restoreCallingIdentity(origId);
23522353

@@ -2429,10 +2430,10 @@ public void setRequestedOrientation(IBinder token,
24292430
return;
24302431
}
24312432
final long origId = Binder.clearCallingIdentity();
2432-
mWindowManager.setAppOrientation(r, requestedOrientation);
2433+
mWindowManager.setAppOrientation(r.appToken, requestedOrientation);
24332434
Configuration config = mWindowManager.updateOrientationFromAppTokens(
24342435
mConfiguration,
2435-
r.mayFreezeScreenLocked(r.app) ? r : null);
2436+
r.mayFreezeScreenLocked(r.app) ? r.appToken : null);
24362437
if (config != null) {
24372438
r.frozenBeforeDestroy = true;
24382439
if (!updateConfigurationLocked(config, r, false)) {
@@ -2449,7 +2450,7 @@ public int getRequestedOrientation(IBinder token) {
24492450
if (r == null) {
24502451
return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
24512452
}
2452-
return mWindowManager.getAppOrientation(r);
2453+
return mWindowManager.getAppOrientation(r.appToken);
24532454
}
24542455
}
24552456

@@ -2515,7 +2516,7 @@ public final void finishHeavyWeightApp() {
25152516
for (int i=0; i<activities.size(); i++) {
25162517
ActivityRecord r = activities.get(i);
25172518
if (!r.finishing) {
2518-
int index = mMainStack.indexOfTokenLocked(r);
2519+
int index = mMainStack.indexOfTokenLocked(r.appToken);
25192520
if (index >= 0) {
25202521
mMainStack.finishActivityLocked(r, index, Activity.RESULT_CANCELED,
25212522
null, "finish-heavy");
@@ -2617,7 +2618,7 @@ public boolean willActivityBeVisible(IBinder token) {
26172618
int i;
26182619
for (i=mMainStack.mHistory.size()-1; i>=0; i--) {
26192620
ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(i);
2620-
if (r == token) {
2621+
if (r.appToken == token) {
26212622
return true;
26222623
}
26232624
if (r.fullscreen && !r.finishing) {
@@ -2705,9 +2706,9 @@ private final void handleAppDiedLocked(ProcessRecord app,
27052706
r.makeFinishing();
27062707
mMainStack.mHistory.remove(i);
27072708
r.takeFromHistory();
2708-
mWindowManager.removeAppToken(r);
2709+
mWindowManager.removeAppToken(r.appToken);
27092710
if (VALIDATE_TOKENS) {
2710-
mWindowManager.validateAppTokens(mMainStack.mHistory);
2711+
mMainStack.validateAppTokensLocked();
27112712
}
27122713
r.removeUriPermissionsLocked();
27132714

@@ -5173,10 +5174,10 @@ public List getTasks(int maxNum, int flags,
51735174
if (topThumbnail != null) {
51745175
if (localLOGV) Slog.v(TAG, "Requesting top thumbnail");
51755176
try {
5176-
topThumbnail.requestThumbnail(topRecord);
5177+
topThumbnail.requestThumbnail(topRecord.appToken);
51775178
} catch (Exception e) {
51785179
Slog.w(TAG, "Exception thrown when requesting thumbnail", e);
5179-
sendPendingThumbnail(null, topRecord, null, null, true);
5180+
sendPendingThumbnail(null, topRecord.appToken, null, null, true);
51805181
}
51815182
}
51825183

@@ -5547,7 +5548,7 @@ int getTaskForActivityLocked(IBinder token, boolean onlyRoot) {
55475548
TaskRecord lastTask = null;
55485549
for (int i=0; i<N; i++) {
55495550
ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(i);
5550-
if (r == token) {
5551+
if (r.appToken == token) {
55515552
if (!onlyRoot || lastTask != r.task) {
55525553
return r.task.taskId;
55535554
}
@@ -5568,7 +5569,7 @@ public void finishOtherInstances(IBinder token, ComponentName className) {
55685569
for (int i=0; i<N; i++) {
55695570
ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(i);
55705571
if (r.realActivity.equals(className)
5571-
&& r != token && lastTask != r.task) {
5572+
&& r.appToken != token && lastTask != r.task) {
55725573
if (r.stack.finishActivityLocked(r, i, Activity.RESULT_CANCELED,
55735574
null, "others")) {
55745575
i--;
@@ -7112,7 +7113,7 @@ private boolean handleAppCrashLocked(ProcessRecord app) {
71127113
// process, then terminate it to avoid getting in a loop.
71137114
Slog.w(TAG, " Force finishing activity "
71147115
+ r.intent.getComponent().flattenToShortString());
7115-
int index = mMainStack.indexOfTokenLocked(r);
7116+
int index = mMainStack.indexOfActivityLocked(r);
71167117
r.stack.finishActivityLocked(r, index,
71177118
Activity.RESULT_CANCELED, null, "crashed");
71187119
// Also terminate any activities below it that aren't yet
@@ -8631,8 +8632,8 @@ private void dumpActivity(String prefix, FileDescriptor fd, PrintWriter pw,
86318632
try {
86328633
TransferPipe tp = new TransferPipe();
86338634
try {
8634-
r.app.thread.dumpActivity(tp.getWriteFd().getFileDescriptor(), r,
8635-
innerPrefix, args);
8635+
r.app.thread.dumpActivity(tp.getWriteFd().getFileDescriptor(),
8636+
r.appToken, innerPrefix, args);
86368637
tp.go(fd);
86378638
} finally {
86388639
tp.kill();
@@ -9048,8 +9049,8 @@ private static final void dumpHistoryList(FileDescriptor fd, PrintWriter pw, Lis
90489049
try {
90499050
TransferPipe tp = new TransferPipe();
90509051
try {
9051-
r.app.thread.dumpActivity(tp.getWriteFd().getFileDescriptor(), r,
9052-
innerPrefix, args);
9052+
r.app.thread.dumpActivity(tp.getWriteFd().getFileDescriptor(),
9053+
r.appToken, innerPrefix, args);
90539054
// Short timeout, since blocking here can
90549055
// deadlock with the application.
90559056
tp.go(fd, 2000);

services/java/com/android/server/am/ActivityRecord.java

Lines changed: 74 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import android.graphics.Bitmap;
3030
import android.os.Build;
3131
import android.os.Bundle;
32+
import android.os.IBinder;
3233
import android.os.Message;
3334
import android.os.Process;
3435
import android.os.RemoteException;
@@ -48,9 +49,10 @@
4849
/**
4950
* An entry in the history stack, representing an activity.
5051
*/
51-
final class ActivityRecord extends IApplicationToken.Stub {
52+
final class ActivityRecord {
5253
final ActivityManagerService service; // owner
5354
final ActivityStack stack; // owner
55+
final IApplicationToken.Stub appToken; // window manager token
5456
final ActivityInfo info; // all about me
5557
final int launchedFromUid; // always the uid who started the activity.
5658
final Intent intent; // the original intent that generated us
@@ -200,13 +202,78 @@ void dump(PrintWriter pw, String prefix) {
200202
}
201203
}
202204

205+
static class Token extends IApplicationToken.Stub {
206+
final WeakReference<ActivityRecord> weakActivity;
207+
208+
Token(ActivityRecord activity) {
209+
weakActivity = new WeakReference<ActivityRecord>(activity);
210+
}
211+
212+
@Override public void windowsDrawn() throws RemoteException {
213+
ActivityRecord activity = weakActivity.get();
214+
if (activity != null) {
215+
activity.windowsDrawn();
216+
}
217+
}
218+
219+
@Override public void windowsVisible() throws RemoteException {
220+
ActivityRecord activity = weakActivity.get();
221+
if (activity != null) {
222+
activity.windowsVisible();
223+
}
224+
}
225+
226+
@Override public void windowsGone() throws RemoteException {
227+
ActivityRecord activity = weakActivity.get();
228+
if (activity != null) {
229+
activity.windowsGone();
230+
}
231+
}
232+
233+
@Override public boolean keyDispatchingTimedOut() throws RemoteException {
234+
ActivityRecord activity = weakActivity.get();
235+
if (activity != null) {
236+
return activity.keyDispatchingTimedOut();
237+
}
238+
return false;
239+
}
240+
241+
@Override public long getKeyDispatchingTimeout() throws RemoteException {
242+
ActivityRecord activity = weakActivity.get();
243+
if (activity != null) {
244+
return activity.getKeyDispatchingTimeout();
245+
}
246+
return 0;
247+
}
248+
249+
public String toString() {
250+
StringBuilder sb = new StringBuilder(128);
251+
sb.append("Token{");
252+
sb.append(Integer.toHexString(System.identityHashCode(this)));
253+
sb.append(' ');
254+
sb.append(weakActivity.get());
255+
sb.append('}');
256+
return sb.toString();
257+
}
258+
}
259+
260+
static ActivityRecord forToken(IBinder token) {
261+
try {
262+
return token != null ? ((Token)token).weakActivity.get() : null;
263+
} catch (ClassCastException e) {
264+
Slog.w(ActivityManagerService.TAG, "Bad activity token: " + token, e);
265+
return null;
266+
}
267+
}
268+
203269
ActivityRecord(ActivityManagerService _service, ActivityStack _stack, ProcessRecord _caller,
204270
int _launchedFromUid, Intent _intent, String _resolvedType,
205271
ActivityInfo aInfo, Configuration _configuration,
206272
ActivityRecord _resultTo, String _resultWho, int _reqCode,
207273
boolean _componentSpecified) {
208274
service = _service;
209275
stack = _stack;
276+
appToken = new Token(this);
210277
info = aInfo;
211278
launchedFromUid = _launchedFromUid;
212279
intent = _intent;
@@ -445,7 +512,7 @@ final void deliverNewIntentLocked(int callingUid, Intent intent) {
445512
ar.add(intent);
446513
service.grantUriPermissionFromIntentLocked(callingUid, packageName,
447514
intent, getUriPermissionsLocked());
448-
app.thread.scheduleNewIntent(ar, this);
515+
app.thread.scheduleNewIntent(ar, appToken);
449516
sent = true;
450517
} catch (RemoteException e) {
451518
Slog.w(ActivityManagerService.TAG,
@@ -470,14 +537,14 @@ void removeUriPermissionsLocked() {
470537
void pauseKeyDispatchingLocked() {
471538
if (!keysPaused) {
472539
keysPaused = true;
473-
service.mWindowManager.pauseKeyDispatching(this);
540+
service.mWindowManager.pauseKeyDispatching(appToken);
474541
}
475542
}
476543

477544
void resumeKeyDispatchingLocked() {
478545
if (keysPaused) {
479546
keysPaused = false;
480-
service.mWindowManager.resumeKeyDispatching(this);
547+
service.mWindowManager.resumeKeyDispatching(appToken);
481548
}
482549
}
483550

@@ -512,14 +579,14 @@ public boolean mayFreezeScreenLocked(ProcessRecord app) {
512579

513580
public void startFreezingScreenLocked(ProcessRecord app, int configChanges) {
514581
if (mayFreezeScreenLocked(app)) {
515-
service.mWindowManager.startAppFreezingScreen(this, configChanges);
582+
service.mWindowManager.startAppFreezingScreen(appToken, configChanges);
516583
}
517584
}
518585

519586
public void stopFreezingScreenLocked(boolean force) {
520587
if (force || frozenBeforeDestroy) {
521588
frozenBeforeDestroy = false;
522-
service.mWindowManager.stopAppFreezingScreen(this, force);
589+
service.mWindowManager.stopAppFreezingScreen(appToken, force);
523590
}
524591
}
525592

@@ -687,7 +754,7 @@ public void setSleeping(boolean _sleeping) {
687754
}
688755
if (app != null && app.thread != null) {
689756
try {
690-
app.thread.scheduleSleeping(this, _sleeping);
757+
app.thread.scheduleSleeping(appToken, _sleeping);
691758
if (sleeping && !stack.mGoingToSleepActivities.contains(this)) {
692759
stack.mGoingToSleepActivities.add(this);
693760
}

0 commit comments

Comments
 (0)