- 증상하드웨어 리셋 이후에 저장된 파일이 날아간다.
- 상세 내용: FileOutputStream을 write후 close해서 DDMS의 File Explorer에 해당 파일이 나타났는데도 하드웨어 리셋을 하면 파일 크기가 0이 되거나 파일이 없어진다.
- 원인: 파일시스템은 버퍼를 활용하고 있다. 버퍼링된 내용이 물리 파일에 씌여지기 전에 하드웨어 리셋이 되기 때문이다.
- 해결책: FileOutputStream객체의 getFD()를 통해 전달받는 FileDescriptor객체를 이용하여 sync() 를 호출하여, 물리파일에 씌여지는 시기를 강제화 한다.
- sync()사용 시의 문제점
- 전화 중과 같은 상황에 sync가 호출 되면 속도가 느려질 수 있다.
- 참고 링크
- Saving Data Safely
2012년 11월 19일 월요일
하드웨어 리셋 이후에 저장된 파일이 날아간다.
Exception없이 Stack Trace를 출력하는 방법
일반적으로 stack trace를 출력하는 방법은 Exception을 이용하는 것이다.
하지만, 디버깅 중 Exception없이 stack trace를 확인하면 도움이 될 경우가 있다.
이럴 경우 아래 클래스를 이용하면 Exception없이도 stack trace를 출력할 수 있다.
public class StackTrace {
public static String toStackTraceString() {
StackTraceElement[] elements = Thread.currentThread().getStackTrace();
StringBuffer buf = new StringBuffer();
for (int i = 0; i < elements.length; i++) {
buf.append(elements[i].toString()).append('\n');
}
return buf.toString();
}
}
하지만, 디버깅 중 Exception없이 stack trace를 확인하면 도움이 될 경우가 있다.
이럴 경우 아래 클래스를 이용하면 Exception없이도 stack trace를 출력할 수 있다.
public class StackTrace {
public static String toStackTraceString() {
StackTraceElement[] elements = Thread.currentThread().getStackTrace();
StringBuffer buf = new StringBuffer();
for (int i = 0; i < elements.length; i++) {
buf.append(elements[i].toString()).append('\n');
}
return buf.toString();
}
}
2012년 11월 9일 금요일
Using HierarchyViewer
HierarchyViewer는 현재 표현하고 있는 View들의 구조 및 특정 View의 상태(속성)를 확인하는데 도움을 준다.
- debugging 중에 특정 View의 레퍼런스를 확인하고, 해당 레퍼런스가 어떤 View인지 찾는데 유용하다.
- Filter by class를 통해 class단위의 Filtering을 제공하고 있다.
- 현재 Filter by id는 동작하지 않는 듯하다. 따라서 class에 의해 filtering한 view들 중에 특정 id를 찾는것에 의해 쉽게 원하는 view를 찾을 수 있다.
- filtering에 의해 특정 view를 찾았다면 해당 view의 각종 property를 확인할 수 있다.
- Property 종류는 아래와 같다.
- Drawing
- Events
- Focus
- Layout
- Measurement
- Miscellaneous
- Padding
- Scrolling
- Text
HierarcheyViewer 캡쳐
2012년 11월 8일 목요일
What is the most accurate memory usage information on adb?
I found the post about this question below and the answer is using 'adb shell procrank'.
The reply of below post is written by Dianne Hackborn the google developer.
https://groups.google.com/forum/?fromgroups=#!topic/android-developers/r9hl8-t0lO0
Q: How calculates memory usage of application
A: "adb shell procrank" is generally the most accurate memory usage information -- in particular uss is the amount of memory private to your app, and pss also includes the shared memory weighted across the number of processes it is shared in. (Ignore the other numbers, they are pretty much useless.)
Q: Thanks for your information, this command is work on emulator, but not
work on my HTC Magic, however it's very useful to me.
A: Ah it may not be installed on a production device. You could also do "adb shell dumpsys meminfo" which will spew a bunch of stuff about the memory in each process, or "adb shell dumpsys meminfo <processname>" for info about your process.
The reply of below post is written by Dianne Hackborn the google developer.
https://groups.google.com/forum/?fromgroups=#!topic/android-developers/r9hl8-t0lO0
Q: How calculates memory usage of application
A: "adb shell procrank" is generally the most accurate memory usage information -- in particular uss is the amount of memory private to your app, and pss also includes the shared memory weighted across the number of processes it is shared in. (Ignore the other numbers, they are pretty much useless.)
Q: Thanks for your information, this command is work on emulator, but not
work on my HTC Magic, however it's very useful to me.
A: Ah it may not be installed on a production device. You could also do "adb shell dumpsys meminfo" which will spew a bunch of stuff about the memory in each process, or "adb shell dumpsys meminfo <processname>" for info about your process.
If you could use root account on adb, you could use 'adb shell procrank' but if not use .adb shell dumpsys meminfo'.
adb top command
시스템 프로세스 상황 모니터링/ 프로세스별 CPU사용량, 메모리와 스왑 사용량 등
top is a command to monitor usage of cpu, memory and swap each system process
Usage: top [ -m max_procs ] [ -n iterations ] [ -d delay ] [ -s sort_column ] [ -t ] [ -h ]
-m num Maximum number of processes to display.
-n num Updates to show before exiting.
-d num Seconds to wait between updates.
-s col Column to sort by (cpu,vss,rss,thr).
-t Show threads instead of processes.
-h Display this help screen.
*** THE START OF EXAMPLE ***
tnkim@tnkim-N53SV:~$ adb shell top -m 10
User 2%, System 2%, IOW 0%, IRQ 0%
User 17 + Nice 0 + Sys 16 + Idle 571 + IOW 1 + IRQ 0 + SIRQ 0 = 605
PID PR CPU% S #THR VSS RSS PCY UID Name
8057 1 2% R 1 988K 392K fg shell top
1275 0 0% S 65 352552K 45472K fg system system_server
306 0 0% S 1 0K 0K fg root spi1
1643 1 0% S 17 290620K 34152K bg app_31 tw.dmb.service
5971 0 0% S 1 0K 0K fg root kworker/0:2
1833 1 0% S 9 276952K 28092K bg app_30 com.thinkware.timesignal
2026 0 0% S 5 4476K 220K fg shell /sbin/adbd
1527 0 0% S 25 307048K 44920K fg app_20 com.thinkware.dixon.nip
1179 1 0% S 16 44680K 5408K fg system /system/bin/surfaceflinger
1813 1 0% S 14 282368K 28656K bg app_28 tw.cardiaryplus.deamon
User 4%, System 3%, IOW 0%, IRQ 0%
User 26 + Nice 0 + Sys 21 + Idle 570 + IOW 0 + IRQ 0 + SIRQ 0 = 617
PID PR CPU% S #THR VSS RSS PCY UID Name
8057 1 2% R 1 992K 404K fg shell top
1275 0 1% S 65 352552K 45472K fg system system_server
306 0 0% D 1 0K 0K fg root spi1
1333 1 0% S 18 306988K 40020K fg system com.android.systemui
1643 0 0% S 17 290620K 34152K bg app_31 tw.dmb.service
802 0 0% S 1 0K 0K fg root tpeg_thread
5971 0 0% S 1 0K 0K fg root kworker/0:2
1527 0 0% S 25 307048K 44920K fg app_20 com.thinkware.dixon.nip
2026 0 0% S 5 4476K 220K fg shell /sbin/adbd
1179 1 0% S 16 44680K 5408K fg system /system/bin/surfaceflinger
top is a command to monitor usage of cpu, memory and swap each system process
Usage: top [ -m max_procs ] [ -n iterations ] [ -d delay ] [ -s sort_column ] [ -t ] [ -h ]
-m num Maximum number of processes to display.
-n num Updates to show before exiting.
-d num Seconds to wait between updates.
-s col Column to sort by (cpu,vss,rss,thr).
-t Show threads instead of processes.
-h Display this help screen.
*** THE START OF EXAMPLE ***
tnkim@tnkim-N53SV:~$ adb shell top -m 10
User 2%, System 2%, IOW 0%, IRQ 0%
User 17 + Nice 0 + Sys 16 + Idle 571 + IOW 1 + IRQ 0 + SIRQ 0 = 605
PID PR CPU% S #THR VSS RSS PCY UID Name
8057 1 2% R 1 988K 392K fg shell top
1275 0 0% S 65 352552K 45472K fg system system_server
306 0 0% S 1 0K 0K fg root spi1
1643 1 0% S 17 290620K 34152K bg app_31 tw.dmb.service
5971 0 0% S 1 0K 0K fg root kworker/0:2
1833 1 0% S 9 276952K 28092K bg app_30 com.thinkware.timesignal
2026 0 0% S 5 4476K 220K fg shell /sbin/adbd
1527 0 0% S 25 307048K 44920K fg app_20 com.thinkware.dixon.nip
1179 1 0% S 16 44680K 5408K fg system /system/bin/surfaceflinger
1813 1 0% S 14 282368K 28656K bg app_28 tw.cardiaryplus.deamon
User 4%, System 3%, IOW 0%, IRQ 0%
User 26 + Nice 0 + Sys 21 + Idle 570 + IOW 0 + IRQ 0 + SIRQ 0 = 617
PID PR CPU% S #THR VSS RSS PCY UID Name
8057 1 2% R 1 992K 404K fg shell top
1275 0 1% S 65 352552K 45472K fg system system_server
306 0 0% D 1 0K 0K fg root spi1
1333 1 0% S 18 306988K 40020K fg system com.android.systemui
1643 0 0% S 17 290620K 34152K bg app_31 tw.dmb.service
802 0 0% S 1 0K 0K fg root tpeg_thread
5971 0 0% S 1 0K 0K fg root kworker/0:2
1527 0 0% S 25 307048K 44920K fg app_20 com.thinkware.dixon.nip
2026 0 0% S 5 4476K 220K fg shell /sbin/adbd
1179 1 0% S 16 44680K 5408K fg system /system/bin/surfaceflinger
...
*** THE END OF EXAMPLE ***
*** THE END OF EXAMPLE ***
2012년 11월 6일 화요일
Service process가 개발자 또는 플랫폼에 의해 강제로 kill된 이후에 다시 시작되는 시간
결론부터 말하면 서비스가 kill 될 때 플랫폼이 재시작 될 시간을 알려주고, 그 시간에 해당 서비스를 재시작합니다.
자세한 사항은 아래와 같습니다.
Service process가 개발자 또는 플랫폼에 의해 강제로 kill된 이후에 다시 시작되는 시간은 친절하게도 플랫폼이 아래와 같은 로그를 표시해 주고 있습니다.
10-23 22:24:51.625: I/ActivityManager(2461): Process com.xxx.yyy (pid 3977) has died.
10-23 22:24:51.630: W/ActivityManager(2461): Scheduling restart of crashed service com.xxx.yyy/.zzz in 20000ms
자세한 사항은 아래와 같습니다.
Service process가 개발자 또는 플랫폼에 의해 강제로 kill된 이후에 다시 시작되는 시간은 친절하게도 플랫폼이 아래와 같은 로그를 표시해 주고 있습니다.
10-23 22:24:51.625: I/ActivityManager(2461): Process com.xxx.yyy (pid 3977) has died.
10-23 22:24:51.630: W/ActivityManager(2461): Scheduling restart of crashed service com.xxx.yyy/.zzz in 20000ms
대략 20초(20000ms)이후에 해당 service가 시작되는 것이 로그로 확인되네요.
10-23 22:25:11.685: I/ActivityManager(2461): Start proc com.xxx.yyy for service com.xxx.yyy/.zzz: pid=4026 uid=10049 gids={}
참고로, Restart정책에 대한 ActivityManagerService.java의 코드는 아래와 같습니다.
소스만 한 번 훑고 지나갑니다~
private final boolean scheduleServiceRestartLocked(ServiceRecord r,
boolean allowCancel) {
boolean canceled = false;
final long now = SystemClock.uptimeMillis();
long minDuration = SERVICE_RESTART_DURATION;
long resetTime = SERVICE_RESET_RUN_DURATION;
if ((r.serviceInfo.applicationInfo.flags
&ApplicationInfo.FLAG_PERSISTENT) != 0) {
minDuration /= 4;
}
// Any delivered but not yet finished starts should be put back
// on the pending list.
final int N = r.deliveredStarts.size();
if (N > 0) {
for (int i=N-1; i>=0; i--) {
ServiceRecord.StartItem si = r.deliveredStarts.get(i);
si.removeUriPermissionsLocked();
if (si.intent == null) {
// We'll generate this again if needed.
} else if (!allowCancel || (si.deliveryCount < ServiceRecord.MAX_DELIVERY_COUNT
&& si.doneExecutingCount < ServiceRecord.MAX_DONE_EXECUTING_COUNT)) {
r.pendingStarts.add(0, si);
long dur = SystemClock.uptimeMillis() - si.deliveredTime;
dur *= 2;
if (minDuration < dur) minDuration = dur;
if (resetTime < dur) resetTime = dur;
} else {
Slog.w(TAG, "Canceling start item " + si.intent + " in service "
+ r.name);
canceled = true;
}
}
r.deliveredStarts.clear();
}
r.totalRestartCount++;
if (r.restartDelay == 0) {
r.restartCount++;
r.restartDelay = minDuration;
} else {
// If it has been a "reasonably long time" since the service
// was started, then reset our restart duration back to
// the beginning, so we don't infinitely increase the duration
// on a service that just occasionally gets killed (which is
// a normal case, due to process being killed to reclaim memory).
if (now > (r.restartTime+resetTime)) {
r.restartCount = 1;
r.restartDelay = minDuration;
} else {
if ((r.serviceInfo.applicationInfo.flags
&ApplicationInfo.FLAG_PERSISTENT) != 0) {
// Services in peristent processes will restart much more
// quickly, since they are pretty important. (Think SystemUI).
r.restartDelay += minDuration/2;
} else {
r.restartDelay *= SERVICE_RESTART_DURATION_FACTOR;
if (r.restartDelay < minDuration) {
r.restartDelay = minDuration;
}
}
}
}
r.nextRestartTime = now + r.restartDelay;
// Make sure that we don't end up restarting a bunch of services
// all at the same time.
boolean repeat;
do {
repeat = false;
for (int i=mRestartingServices.size()-1; i>=0; i--) {
ServiceRecord r2 = mRestartingServices.get(i);
if (r2 != r && r.nextRestartTime
>= (r2.nextRestartTime-SERVICE_MIN_RESTART_TIME_BETWEEN)
&& r.nextRestartTime
< (r2.nextRestartTime+SERVICE_MIN_RESTART_TIME_BETWEEN)) {
r.nextRestartTime = r2.nextRestartTime + SERVICE_MIN_RESTART_TIME_BETWEEN;
r.restartDelay = r.nextRestartTime - now;
repeat = true;
break;
}
}
} while (repeat);
if (!mRestartingServices.contains(r)) {
mRestartingServices.add(r);
}
r.cancelNotification();
mHandler.removeCallbacks(r.restarter);
mHandler.postAtTime(r.restarter, r.nextRestartTime);
r.nextRestartTime = SystemClock.uptimeMillis() + r.restartDelay;
Slog.w(TAG, "Scheduling restart of crashed service "
+ r.shortName + " in " + r.restartDelay + "ms");
EventLog.writeEvent(EventLogTags.AM_SCHEDULE_SERVICE_RESTART,
r.shortName, r.restartDelay);
return canceled;
}
10-23 22:25:11.685: I/ActivityManager(2461): Start proc com.xxx.yyy for service com.xxx.yyy/.zzz: pid=4026 uid=10049 gids={}
참고로, Restart정책에 대한 ActivityManagerService.java의 코드는 아래와 같습니다.
소스만 한 번 훑고 지나갑니다~
private final boolean scheduleServiceRestartLocked(ServiceRecord r,
boolean allowCancel) {
boolean canceled = false;
final long now = SystemClock.uptimeMillis();
long minDuration = SERVICE_RESTART_DURATION;
long resetTime = SERVICE_RESET_RUN_DURATION;
if ((r.serviceInfo.applicationInfo.flags
&ApplicationInfo.FLAG_PERSISTENT) != 0) {
minDuration /= 4;
}
// Any delivered but not yet finished starts should be put back
// on the pending list.
final int N = r.deliveredStarts.size();
if (N > 0) {
for (int i=N-1; i>=0; i--) {
ServiceRecord.StartItem si = r.deliveredStarts.get(i);
si.removeUriPermissionsLocked();
if (si.intent == null) {
// We'll generate this again if needed.
} else if (!allowCancel || (si.deliveryCount < ServiceRecord.MAX_DELIVERY_COUNT
&& si.doneExecutingCount < ServiceRecord.MAX_DONE_EXECUTING_COUNT)) {
r.pendingStarts.add(0, si);
long dur = SystemClock.uptimeMillis() - si.deliveredTime;
dur *= 2;
if (minDuration < dur) minDuration = dur;
if (resetTime < dur) resetTime = dur;
} else {
Slog.w(TAG, "Canceling start item " + si.intent + " in service "
+ r.name);
canceled = true;
}
}
r.deliveredStarts.clear();
}
r.totalRestartCount++;
if (r.restartDelay == 0) {
r.restartCount++;
r.restartDelay = minDuration;
} else {
// If it has been a "reasonably long time" since the service
// was started, then reset our restart duration back to
// the beginning, so we don't infinitely increase the duration
// on a service that just occasionally gets killed (which is
// a normal case, due to process being killed to reclaim memory).
if (now > (r.restartTime+resetTime)) {
r.restartCount = 1;
r.restartDelay = minDuration;
} else {
if ((r.serviceInfo.applicationInfo.flags
&ApplicationInfo.FLAG_PERSISTENT) != 0) {
// Services in peristent processes will restart much more
// quickly, since they are pretty important. (Think SystemUI).
r.restartDelay += minDuration/2;
} else {
r.restartDelay *= SERVICE_RESTART_DURATION_FACTOR;
if (r.restartDelay < minDuration) {
r.restartDelay = minDuration;
}
}
}
}
r.nextRestartTime = now + r.restartDelay;
// Make sure that we don't end up restarting a bunch of services
// all at the same time.
boolean repeat;
do {
repeat = false;
for (int i=mRestartingServices.size()-1; i>=0; i--) {
ServiceRecord r2 = mRestartingServices.get(i);
if (r2 != r && r.nextRestartTime
>= (r2.nextRestartTime-SERVICE_MIN_RESTART_TIME_BETWEEN)
&& r.nextRestartTime
< (r2.nextRestartTime+SERVICE_MIN_RESTART_TIME_BETWEEN)) {
r.nextRestartTime = r2.nextRestartTime + SERVICE_MIN_RESTART_TIME_BETWEEN;
r.restartDelay = r.nextRestartTime - now;
repeat = true;
break;
}
}
} while (repeat);
if (!mRestartingServices.contains(r)) {
mRestartingServices.add(r);
}
r.cancelNotification();
mHandler.removeCallbacks(r.restarter);
mHandler.postAtTime(r.restarter, r.nextRestartTime);
r.nextRestartTime = SystemClock.uptimeMillis() + r.restartDelay;
Slog.w(TAG, "Scheduling restart of crashed service "
+ r.shortName + " in " + r.restartDelay + "ms");
EventLog.writeEvent(EventLogTags.AM_SCHEDULE_SERVICE_RESTART,
r.shortName, r.restartDelay);
return canceled;
}
피드 구독하기:
글 (Atom)

