Skip to content

Commit df3228e

Browse files
Dianne HackbornAndroid Git Automerger
authored andcommitted
am ce06c00: Merge "Debugging code for #6169553: Make Phone launch faster" into ics-mr1
* commit 'ce06c000b4133c63414c3244c3325e25315ab179': Debugging code for #6169553: Make Phone launch faster
2 parents 6b16363 + ce06c00 commit df3228e

File tree

4 files changed

+169
-12
lines changed

4 files changed

+169
-12
lines changed

cmds/dumpstate/dumpstate.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,24 @@ static void dumpstate() {
108108
dump_file("VM TRACES AT LAST ANR", anr_traces_path);
109109
}
110110

111+
/* slow traces for slow operations */
112+
if (anr_traces_path[0] != 0) {
113+
int tail = strlen(anr_traces_path)-1;
114+
while (tail > 0 && anr_traces_path[tail] != '/') {
115+
tail--;
116+
}
117+
int i = 0;
118+
while (1) {
119+
sprintf(anr_traces_path+tail+1, "slow%02d.txt", i);
120+
if (stat(anr_traces_path, &st)) {
121+
// No traces file at this index, done with the files.
122+
break;
123+
}
124+
dump_file("VM TRACES WHEN SLOW", anr_traces_path);
125+
i++;
126+
}
127+
}
128+
111129
// dump_file("EVENT LOG TAGS", "/etc/event-log-tags");
112130
run_command("EVENT LOG", 20, "logcat", "-b", "events", "-v", "threadtime", "-d", "*:v", NULL);
113131
run_command("RADIO LOG", 20, "logcat", "-b", "radio", "-v", "threadtime", "-d", "*:v", NULL);

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

Lines changed: 91 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@
105105
import android.os.SystemClock;
106106
import android.os.SystemProperties;
107107
import android.provider.Settings;
108+
import android.text.format.Time;
108109
import android.util.EventLog;
109110
import android.util.Pair;
110111
import android.util.Slog;
@@ -186,6 +187,8 @@ public final class ActivityManagerService extends ActivityManagerNative
186187

187188
private static final String SYSTEM_DEBUGGABLE = "ro.debuggable";
188189

190+
static final boolean IS_USER_BUILD = "user".equals(Build.TYPE);
191+
189192
// Maximum number of recent tasks that we can remember.
190193
static final int MAX_RECENT_TASKS = 20;
191194

@@ -2904,6 +2907,12 @@ public static File dumpStackTraces(boolean clearTraces, ArrayList<Integer> first
29042907
return null;
29052908
}
29062909

2910+
dumpStackTraces(tracesPath, firstPids, processStats, lastPids);
2911+
return tracesFile;
2912+
}
2913+
2914+
private static void dumpStackTraces(String tracesPath, ArrayList<Integer> firstPids,
2915+
ProcessStats processStats, SparseArray<Boolean> lastPids) {
29072916
// Use a FileObserver to detect when traces finish writing.
29082917
// The order of traces is considered important to maintain for legibility.
29092918
FileObserver observer = new FileObserver(tracesPath, FileObserver.CLOSE_WRITE) {
@@ -2914,16 +2923,18 @@ public static File dumpStackTraces(boolean clearTraces, ArrayList<Integer> first
29142923
observer.startWatching();
29152924

29162925
// First collect all of the stacks of the most important pids.
2917-
try {
2918-
int num = firstPids.size();
2919-
for (int i = 0; i < num; i++) {
2920-
synchronized (observer) {
2921-
Process.sendSignal(firstPids.get(i), Process.SIGNAL_QUIT);
2922-
observer.wait(200); // Wait for write-close, give up after 200msec
2926+
if (firstPids != null) {
2927+
try {
2928+
int num = firstPids.size();
2929+
for (int i = 0; i < num; i++) {
2930+
synchronized (observer) {
2931+
Process.sendSignal(firstPids.get(i), Process.SIGNAL_QUIT);
2932+
observer.wait(200); // Wait for write-close, give up after 200msec
2933+
}
29232934
}
2935+
} catch (InterruptedException e) {
2936+
Log.wtf(TAG, e);
29242937
}
2925-
} catch (InterruptedException e) {
2926-
Log.wtf(TAG, e);
29272938
}
29282939

29292940
// Next measure CPU usage.
@@ -2959,8 +2970,6 @@ public static File dumpStackTraces(boolean clearTraces, ArrayList<Integer> first
29592970
}
29602971
}
29612972

2962-
return tracesFile;
2963-
29642973
} finally {
29652974
observer.stopWatching();
29662975
}
@@ -2981,6 +2990,78 @@ public void run() {
29812990
}
29822991
}
29832992

2993+
final void logAppTooSlow(ProcessRecord app, long startTime, String msg) {
2994+
if (IS_USER_BUILD) {
2995+
return;
2996+
}
2997+
String tracesPath = SystemProperties.get("dalvik.vm.stack-trace-file", null);
2998+
if (tracesPath == null || tracesPath.length() == 0) {
2999+
return;
3000+
}
3001+
3002+
StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
3003+
StrictMode.allowThreadDiskWrites();
3004+
try {
3005+
final File tracesFile = new File(tracesPath);
3006+
final File tracesDir = tracesFile.getParentFile();
3007+
final File tracesTmp = new File(tracesDir, "__tmp__");
3008+
try {
3009+
if (!tracesDir.exists()) tracesFile.mkdirs();
3010+
FileUtils.setPermissions(tracesDir.getPath(), 0775, -1, -1); // drwxrwxr-x
3011+
3012+
if (tracesFile.exists()) {
3013+
tracesTmp.delete();
3014+
tracesFile.renameTo(tracesTmp);
3015+
}
3016+
StringBuilder sb = new StringBuilder();
3017+
Time tobj = new Time();
3018+
tobj.set(System.currentTimeMillis());
3019+
sb.append(tobj.format("%Y-%m-%d %H:%M:%S"));
3020+
sb.append(": ");
3021+
TimeUtils.formatDuration(SystemClock.uptimeMillis()-startTime, sb);
3022+
sb.append(" since ");
3023+
sb.append(msg);
3024+
FileOutputStream fos = new FileOutputStream(tracesFile);
3025+
fos.write(sb.toString().getBytes());
3026+
if (app == null) {
3027+
fos.write("\n*** No application process!".getBytes());
3028+
}
3029+
fos.close();
3030+
FileUtils.setPermissions(tracesFile.getPath(), 0666, -1, -1); // -rw-rw-rw-
3031+
} catch (IOException e) {
3032+
Slog.w(TAG, "Unable to prepare slow app traces file: " + tracesPath, e);
3033+
return;
3034+
}
3035+
3036+
if (app != null) {
3037+
ArrayList<Integer> firstPids = new ArrayList<Integer>();
3038+
firstPids.add(app.pid);
3039+
dumpStackTraces(tracesPath, firstPids, null, null);
3040+
}
3041+
3042+
File lastTracesFile = null;
3043+
File curTracesFile = null;
3044+
for (int i=9; i>=0; i--) {
3045+
String name = String.format("slow%02d.txt", i);
3046+
curTracesFile = new File(tracesDir, name);
3047+
if (curTracesFile.exists()) {
3048+
if (lastTracesFile != null) {
3049+
curTracesFile.renameTo(lastTracesFile);
3050+
} else {
3051+
curTracesFile.delete();
3052+
}
3053+
}
3054+
lastTracesFile = curTracesFile;
3055+
}
3056+
tracesFile.renameTo(curTracesFile);
3057+
if (tracesTmp.exists()) {
3058+
tracesTmp.renameTo(tracesFile);
3059+
}
3060+
} finally {
3061+
StrictMode.setThreadPolicy(oldPolicy);
3062+
}
3063+
}
3064+
29843065
final void appNotResponding(ProcessRecord app, ActivityRecord activity,
29853066
ActivityRecord parent, final String annotation) {
29863067
ArrayList<Integer> firstPids = new ArrayList<Integer>(5);

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

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,8 @@ final class ActivityRecord {
8282
long startTime; // last time this activity was started
8383
long lastVisibleTime; // last time this activity became visible
8484
long cpuTimeAtResume; // the cpu time of host process at the time of resuming activity
85+
long pauseTime; // last time we started pausing the activity
86+
long launchTickTime; // base time for launch tick messages
8587
Configuration configuration; // configuration activity was last running in
8688
CompatibilityInfo compat;// last used compatibility mode
8789
ActivityRecord resultTo; // who started this entry, so will get our reply
@@ -572,6 +574,32 @@ void clearThumbnail() {
572574
}
573575
}
574576

577+
void startLaunchTickingLocked() {
578+
if (ActivityManagerService.IS_USER_BUILD) {
579+
return;
580+
}
581+
if (launchTickTime == 0) {
582+
launchTickTime = SystemClock.uptimeMillis();
583+
continueLaunchTickingLocked();
584+
}
585+
}
586+
587+
boolean continueLaunchTickingLocked() {
588+
if (launchTickTime != 0) {
589+
Message msg = stack.mHandler.obtainMessage(ActivityStack.LAUNCH_TICK_MSG);
590+
msg.obj = this;
591+
stack.mHandler.removeMessages(ActivityStack.LAUNCH_TICK_MSG);
592+
stack.mHandler.sendMessageDelayed(msg, ActivityStack.LAUNCH_TICK);
593+
return true;
594+
}
595+
return false;
596+
}
597+
598+
void finishLaunchTickingLocked() {
599+
launchTickTime = 0;
600+
stack.mHandler.removeMessages(ActivityStack.LAUNCH_TICK_MSG);
601+
}
602+
575603
// IApplicationToken
576604

577605
public boolean mayFreezeScreenLocked(ProcessRecord app) {
@@ -627,6 +655,7 @@ public void windowsDrawn() {
627655
stack.mInitialStartTime = 0;
628656
}
629657
startTime = 0;
658+
finishLaunchTickingLocked();
630659
}
631660
}
632661

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

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,10 @@ final class ActivityStack {
9595
// How long we wait until giving up on the last activity telling us it
9696
// is idle.
9797
static final int IDLE_TIMEOUT = 10*1000;
98-
98+
99+
// Ticks during which we check progress while waiting for an app to launch.
100+
static final int LAUNCH_TICK = 500;
101+
99102
// How long we wait until giving up on the last activity to pause. This
100103
// is short because it directly impacts the responsiveness of starting the
101104
// next activity.
@@ -278,10 +281,11 @@ enum ActivityState {
278281
static final int PAUSE_TIMEOUT_MSG = 9;
279282
static final int IDLE_TIMEOUT_MSG = 10;
280283
static final int IDLE_NOW_MSG = 11;
284+
static final int LAUNCH_TICK_MSG = 12;
281285
static final int LAUNCH_TIMEOUT_MSG = 16;
282286
static final int DESTROY_TIMEOUT_MSG = 17;
283287
static final int RESUME_TOP_ACTIVITY_MSG = 19;
284-
288+
285289
final Handler mHandler = new Handler() {
286290
//public Handler() {
287291
// if (localLOGV) Slog.v(TAG, "Handler started!");
@@ -303,6 +307,13 @@ public void handleMessage(Message msg) {
303307
// We don't at this point know if the activity is fullscreen,
304308
// so we need to be conservative and assume it isn't.
305309
Slog.w(TAG, "Activity pause timeout for " + r);
310+
synchronized (mService) {
311+
if (r.app != null) {
312+
mService.logAppTooSlow(r.app, r.pauseTime,
313+
"pausing " + r);
314+
}
315+
}
316+
306317
activityPaused(r != null ? r.appToken : null, true);
307318
} break;
308319
case IDLE_TIMEOUT_MSG: {
@@ -319,6 +330,15 @@ public void handleMessage(Message msg) {
319330
Slog.w(TAG, "Activity idle timeout for " + r);
320331
activityIdleInternal(r != null ? r.appToken : null, true, null);
321332
} break;
333+
case LAUNCH_TICK_MSG: {
334+
ActivityRecord r = (ActivityRecord)msg.obj;
335+
synchronized (mService) {
336+
if (r.continueLaunchTickingLocked()) {
337+
mService.logAppTooSlow(r.app, r.launchTickTime,
338+
"launching " + r);
339+
}
340+
}
341+
} break;
322342
case DESTROY_TIMEOUT_MSG: {
323343
ActivityRecord r = (ActivityRecord)msg.obj;
324344
// We don't at this point know if the activity is fullscreen,
@@ -518,6 +538,9 @@ final boolean realStartActivityLocked(ActivityRecord r,
518538
r.startFreezingScreenLocked(app, 0);
519539
mService.mWindowManager.setAppVisibility(r.appToken, true);
520540

541+
// schedule launch ticks to collect information about slow apps.
542+
r.startLaunchTickingLocked();
543+
521544
// Have the window manager re-evaluate the orientation of
522545
// the screen based on the new activity order. Note that
523546
// as a result of this, it can call back into the activity
@@ -900,6 +923,7 @@ private final void startPausingLocked(boolean userLeaving, boolean uiSleeping) {
900923
// responsiveness seen by the user.
901924
Message msg = mHandler.obtainMessage(PAUSE_TIMEOUT_MSG);
902925
msg.obj = prev;
926+
prev.pauseTime = SystemClock.uptimeMillis();
903927
mHandler.sendMessageDelayed(msg, PAUSE_TIMEOUT);
904928
if (DEBUG_PAUSE) Slog.v(TAG, "Waiting for pause to complete...");
905929
} else {
@@ -1443,6 +1467,9 @@ final boolean resumeTopActivityLocked(ActivityRecord prev) {
14431467
// This activity is now becoming visible.
14441468
mService.mWindowManager.setAppVisibility(next.appToken, true);
14451469

1470+
// schedule launch ticks to collect information about slow apps.
1471+
next.startLaunchTickingLocked();
1472+
14461473
ActivityRecord lastResumedActivity = mResumedActivity;
14471474
ActivityState lastState = next.state;
14481475

@@ -3218,6 +3245,7 @@ final ActivityRecord activityIdleInternal(IBinder token, boolean fromTimeout,
32183245
ActivityRecord r = ActivityRecord.forToken(token);
32193246
if (r != null) {
32203247
mHandler.removeMessages(IDLE_TIMEOUT_MSG, r);
3248+
r.finishLaunchTickingLocked();
32213249
}
32223250

32233251
// Get the activity record.
@@ -3588,6 +3616,7 @@ final void cleanUpActivityLocked(ActivityRecord r, boolean cleanServices,
35883616
mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
35893617
mHandler.removeMessages(IDLE_TIMEOUT_MSG, r);
35903618
mHandler.removeMessages(DESTROY_TIMEOUT_MSG, r);
3619+
r.finishLaunchTickingLocked();
35913620
}
35923621

35933622
final void removeActivityFromHistoryLocked(ActivityRecord r) {

0 commit comments

Comments
 (0)