Merge "Further refactoring of the bootchart code."
This commit is contained in:
commit
bf7560f12c
|
@ -1,46 +0,0 @@
|
|||
This version of init contains code to perform "bootcharting", i.e. generating log
|
||||
files that can be later processed by the tools provided by www.bootchart.org.
|
||||
|
||||
On the emulator, use the new -bootchart <timeout> option to boot with bootcharting
|
||||
activated for <timeout> seconds.
|
||||
|
||||
Otherwise, flash your device, and start it. Then create a file on the /data partition
|
||||
with a command like the following:
|
||||
|
||||
adb shell 'echo $TIMEOUT > /data/bootchart/start'
|
||||
|
||||
Where the value of $TIMEOUT corresponds to the wanted bootcharted period in seconds;
|
||||
for example, to bootchart for 2 minutes, do:
|
||||
|
||||
adb shell 'echo 120 > /data/bootchart/start'
|
||||
|
||||
Reboot your device, bootcharting will begin and stop after the period you gave.
|
||||
You can also stop the bootcharting at any moment by doing the following:
|
||||
|
||||
adb shell 'echo 1 > /data/bootchart/stop'
|
||||
|
||||
Note that /data/bootchart/stop is deleted automatically by init at the end of the
|
||||
bootcharting. This is not the case of /data/bootchart/start, so don't forget to delete it
|
||||
when you're done collecting data:
|
||||
|
||||
adb shell rm /data/bootchart/start
|
||||
|
||||
The log files are placed in /data/bootchart/. You must run the script tools/grab-bootchart.sh
|
||||
which will use ADB to retrieve them and create a bootchart.tgz file that can be used with
|
||||
the bootchart parser/renderer, or even uploaded directly to the form located at:
|
||||
|
||||
http://www.bootchart.org/download.html
|
||||
|
||||
NOTE: the bootchart.org webform doesn't seem to work at the moment, you can generate an
|
||||
image on your machine by doing the following:
|
||||
|
||||
1/ download the sources from www.bootchart.org
|
||||
2/ unpack them
|
||||
3/ in the source directory, type 'ant' to build the bootchart program
|
||||
4/ type 'java -jar bootchart.jar /path/to/bootchart.tgz
|
||||
|
||||
technical note:
|
||||
|
||||
This implementation of bootcharting does not use the 'bootchartd' script provided by
|
||||
www.bootchart.org, but a C re-implementation that is directly compiled into our init
|
||||
program.
|
|
@ -14,15 +14,10 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/* this code is used to generate a boot sequence profile that can be used
|
||||
* with the 'bootchart' graphics generation tool. see www.bootchart.org
|
||||
* note that unlike the original bootchartd, this is not a Bash script but
|
||||
* some C code that is run right from the init script.
|
||||
*/
|
||||
|
||||
#include "bootchart.h"
|
||||
#include "keywords.h"
|
||||
#include "log.h"
|
||||
#include "property_service.h"
|
||||
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
|
@ -31,15 +26,14 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define BOOTCHART_POLLING_MS 200 /* polling period in ms */
|
||||
#define BOOTCHART_DEFAULT_TIME_SEC (2*60) /* default polling time in seconds */
|
||||
#define BOOTCHART_MAX_TIME_SEC (10*60) /* max polling time in seconds */
|
||||
#include <string>
|
||||
|
||||
#include <utils/file.h>
|
||||
|
||||
#define VERSION "0.8"
|
||||
#define SAMPLE_PERIOD 0.2
|
||||
#define LOG_ROOT "/data/bootchart"
|
||||
#define LOG_STAT LOG_ROOT"/proc_stat.log"
|
||||
#define LOG_PROCS LOG_ROOT"/proc_ps.log"
|
||||
|
@ -50,257 +44,133 @@
|
|||
#define LOG_STARTFILE LOG_ROOT"/start"
|
||||
#define LOG_STOPFILE LOG_ROOT"/stop"
|
||||
|
||||
#define FILE_BUFF_SIZE 65536
|
||||
// Polling period in ms.
|
||||
static const int BOOTCHART_POLLING_MS = 200;
|
||||
|
||||
struct FileBuff {
|
||||
int count;
|
||||
int fd;
|
||||
char data[FILE_BUFF_SIZE];
|
||||
};
|
||||
// Default polling time in seconds.
|
||||
static const int BOOTCHART_DEFAULT_TIME_SEC = 2*60;
|
||||
|
||||
static long long last_bootchart_time;
|
||||
// Max polling time in seconds.
|
||||
static const int BOOTCHART_MAX_TIME_SEC = 10*60;
|
||||
|
||||
static long long g_last_bootchart_time;
|
||||
static int g_remaining_samples;
|
||||
|
||||
static FileBuff log_stat[1];
|
||||
static FileBuff log_procs[1];
|
||||
static FileBuff log_disks[1];
|
||||
static FILE* log_stat;
|
||||
static FILE* log_procs;
|
||||
static FILE* log_disks;
|
||||
|
||||
static int
|
||||
proc_read(const char* filename, char* buff, size_t buffsize)
|
||||
{
|
||||
int len = 0;
|
||||
int fd = open(filename, O_RDONLY | O_CLOEXEC);
|
||||
if (fd >= 0) {
|
||||
len = TEMP_FAILURE_RETRY(read(fd, buff, buffsize-1));
|
||||
close(fd);
|
||||
static long long get_uptime_jiffies() {
|
||||
std::string uptime;
|
||||
if (!android::ReadFileToString("/proc/uptime", &uptime)) {
|
||||
return 0;
|
||||
}
|
||||
buff[len > 0 ? len : 0] = 0;
|
||||
return len;
|
||||
return 100LL * strtod(uptime.c_str(), NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
file_buff_open( FileBuff* buff, const char* path )
|
||||
{
|
||||
buff->count = 0;
|
||||
buff->fd = open(path, O_WRONLY|O_CREAT|O_TRUNC|O_CLOEXEC, 0755);
|
||||
}
|
||||
static void log_header() {
|
||||
char date[32];
|
||||
time_t now_t = time(NULL);
|
||||
struct tm now = *localtime(&now_t);
|
||||
strftime(date, sizeof(date), "%F %T", &now);
|
||||
|
||||
static void
|
||||
file_buff_write( FileBuff* buff, const void* src, int len )
|
||||
{
|
||||
while (len > 0) {
|
||||
int avail = sizeof(buff->data) - buff->count;
|
||||
if (avail > len)
|
||||
avail = len;
|
||||
|
||||
memcpy( buff->data + buff->count, src, avail );
|
||||
len -= avail;
|
||||
src = (char*)src + avail;
|
||||
|
||||
buff->count += avail;
|
||||
if (buff->count == FILE_BUFF_SIZE) {
|
||||
TEMP_FAILURE_RETRY(write(buff->fd, buff->data, buff->count));
|
||||
buff->count = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
file_buff_done( FileBuff* buff )
|
||||
{
|
||||
if (buff->count > 0) {
|
||||
TEMP_FAILURE_RETRY(write(buff->fd, buff->data, buff->count));
|
||||
buff->count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static long long
|
||||
get_uptime_jiffies()
|
||||
{
|
||||
char buff[64];
|
||||
long long jiffies = 0;
|
||||
|
||||
if (proc_read("/proc/uptime", buff, sizeof(buff)) > 0)
|
||||
jiffies = 100LL*strtod(buff,NULL);
|
||||
|
||||
return jiffies;
|
||||
}
|
||||
|
||||
static void
|
||||
log_header(void)
|
||||
{
|
||||
FILE* out;
|
||||
char cmdline[1024];
|
||||
char uname[128];
|
||||
char cpuinfo[128];
|
||||
char* cpu;
|
||||
char date[32];
|
||||
time_t now_t = time(NULL);
|
||||
struct tm now = *localtime(&now_t);
|
||||
strftime(date, sizeof(date), "%x %X", &now);
|
||||
|
||||
out = fopen( LOG_HEADER, "we" );
|
||||
if (out == NULL)
|
||||
utsname uts;
|
||||
if (uname(&uts) == -1) {
|
||||
return;
|
||||
|
||||
proc_read("/proc/cmdline", cmdline, sizeof(cmdline));
|
||||
proc_read("/proc/version", uname, sizeof(uname));
|
||||
proc_read("/proc/cpuinfo", cpuinfo, sizeof(cpuinfo));
|
||||
|
||||
cpu = strchr( cpuinfo, ':' );
|
||||
if (cpu) {
|
||||
char* p = strchr(cpu, '\n');
|
||||
cpu += 2;
|
||||
if (p)
|
||||
*p = 0;
|
||||
}
|
||||
|
||||
fprintf(out, "version = %s\n", VERSION);
|
||||
fprintf(out, "title = Boot chart for Android ( %s )\n", date);
|
||||
fprintf(out, "system.uname = %s\n", uname);
|
||||
fprintf(out, "system.release = 0.0\n");
|
||||
fprintf(out, "system.cpu = %s\n", cpu);
|
||||
fprintf(out, "system.kernel.options = %s\n", cmdline);
|
||||
char fingerprint[PROP_VALUE_MAX];
|
||||
if (property_get("ro.build.fingerprint", fingerprint) == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::string kernel_cmdline;
|
||||
android::ReadFileToString("/proc/cmdline", &kernel_cmdline);
|
||||
|
||||
FILE* out = fopen(LOG_HEADER, "we");
|
||||
if (out == NULL) {
|
||||
return;
|
||||
}
|
||||
fprintf(out, "version = Android init 0.8 " __TIME__ "\n");
|
||||
fprintf(out, "title = Boot chart for Android (%s)\n", date);
|
||||
fprintf(out, "system.uname = %s %s %s %s\n", uts.sysname, uts.release, uts.version, uts.machine);
|
||||
fprintf(out, "system.release = %s\n", fingerprint);
|
||||
// TODO: use /proc/cpuinfo "model name" line for x86, "Processor" line for arm.
|
||||
fprintf(out, "system.cpu = %s\n", uts.machine);
|
||||
fprintf(out, "system.kernel.options = %s\n", kernel_cmdline.c_str());
|
||||
fclose(out);
|
||||
}
|
||||
|
||||
static void
|
||||
do_log_uptime(FileBuff* log)
|
||||
{
|
||||
char buff[65];
|
||||
int len;
|
||||
|
||||
snprintf(buff,sizeof(buff),"%lld\n",get_uptime_jiffies());
|
||||
len = strlen(buff);
|
||||
file_buff_write(log, buff, len);
|
||||
static void do_log_uptime(FILE* log) {
|
||||
fprintf(log, "%lld\n", get_uptime_jiffies());
|
||||
}
|
||||
|
||||
static void
|
||||
do_log_ln(FileBuff* log)
|
||||
{
|
||||
file_buff_write(log, "\n", 1);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
do_log_file(FileBuff* log, const char* procfile)
|
||||
{
|
||||
char buff[1024];
|
||||
int fd;
|
||||
|
||||
static void do_log_file(FILE* log, const char* procfile) {
|
||||
do_log_uptime(log);
|
||||
|
||||
/* append file content */
|
||||
fd = open(procfile,O_RDONLY|O_CLOEXEC);
|
||||
if (fd >= 0) {
|
||||
for (;;) {
|
||||
int ret = TEMP_FAILURE_RETRY(read(fd, buff, sizeof(buff)));
|
||||
if (ret <= 0)
|
||||
break;
|
||||
|
||||
file_buff_write(log, buff, ret);
|
||||
if (ret < (int)sizeof(buff))
|
||||
break;
|
||||
}
|
||||
close(fd);
|
||||
std::string content;
|
||||
if (android::ReadFileToString(procfile, &content)) {
|
||||
fprintf(log, "%s\n", content.c_str());
|
||||
}
|
||||
|
||||
do_log_ln(log);
|
||||
}
|
||||
|
||||
static void
|
||||
do_log_procs(FileBuff* log)
|
||||
{
|
||||
DIR* dir = opendir("/proc");
|
||||
struct dirent* entry;
|
||||
|
||||
static void do_log_procs(FILE* log) {
|
||||
do_log_uptime(log);
|
||||
|
||||
DIR* dir = opendir("/proc");
|
||||
struct dirent* entry;
|
||||
while ((entry = readdir(dir)) != NULL) {
|
||||
/* only match numeric values */
|
||||
char* end;
|
||||
int pid = strtol( entry->d_name, &end, 10);
|
||||
// Only match numeric values.
|
||||
char* end;
|
||||
int pid = strtol(entry->d_name, &end, 10);
|
||||
if (end != NULL && end > entry->d_name && *end == 0) {
|
||||
char filename[32];
|
||||
char buff[1024];
|
||||
char cmdline[1024];
|
||||
int len;
|
||||
int fd;
|
||||
char filename[32];
|
||||
|
||||
/* read command line and extract program name */
|
||||
snprintf(filename,sizeof(filename),"/proc/%d/cmdline",pid);
|
||||
proc_read(filename, cmdline, sizeof(cmdline));
|
||||
// /proc/<pid>/stat only has truncated task names, so get the full
|
||||
// name from /proc/<pid>/cmdline.
|
||||
snprintf(filename, sizeof(filename), "/proc/%d/cmdline", pid);
|
||||
std::string cmdline;
|
||||
android::ReadFileToString(filename, &cmdline);
|
||||
const char* full_name = cmdline.c_str(); // So we stop at the first NUL.
|
||||
|
||||
/* read process stat line */
|
||||
snprintf(filename,sizeof(filename),"/proc/%d/stat",pid);
|
||||
fd = open(filename,O_RDONLY|O_CLOEXEC);
|
||||
if (fd >= 0) {
|
||||
len = TEMP_FAILURE_RETRY(read(fd, buff, sizeof(buff)-1));
|
||||
close(fd);
|
||||
if (len > 0) {
|
||||
int len2 = strlen(cmdline);
|
||||
if (len2 > 0) {
|
||||
/* we want to substitute the process name with its real name */
|
||||
const char* p1;
|
||||
const char* p2;
|
||||
buff[len] = 0;
|
||||
p1 = strchr(buff, '(');
|
||||
p2 = strchr(p1, ')');
|
||||
file_buff_write(log, buff, p1+1-buff);
|
||||
file_buff_write(log, cmdline, strlen(cmdline));
|
||||
file_buff_write(log, p2, strlen(p2));
|
||||
} else {
|
||||
/* no substitution */
|
||||
file_buff_write(log,buff,len);
|
||||
// Read process stat line.
|
||||
snprintf(filename, sizeof(filename), "/proc/%d/stat", pid);
|
||||
std::string stat;
|
||||
if (android::ReadFileToString(filename, &stat)) {
|
||||
if (!cmdline.empty()) {
|
||||
// Substitute the process name with its real name.
|
||||
size_t open = stat.find('(');
|
||||
size_t close = stat.find_last_of(')');
|
||||
if (open != std::string::npos && close != std::string::npos) {
|
||||
stat.replace(open + 1, close - open - 1, full_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
fputs(stat.c_str(), log);
|
||||
}
|
||||
}
|
||||
}
|
||||
closedir(dir);
|
||||
do_log_ln(log);
|
||||
|
||||
fputc('\n', log);
|
||||
}
|
||||
|
||||
int do_bootchart_init(int nargs, char **args)
|
||||
{
|
||||
g_remaining_samples = bootchart_init();
|
||||
if (g_remaining_samples < 0) {
|
||||
ERROR("bootcharting init failure\n");
|
||||
} else if (g_remaining_samples > 0) {
|
||||
NOTICE("bootcharting started (will run for %d ms)\n", g_remaining_samples*BOOTCHART_POLLING_MS);
|
||||
static int bootchart_init() {
|
||||
int timeout = 0;
|
||||
|
||||
std::string start;
|
||||
android::ReadFileToString(LOG_STARTFILE, &start);
|
||||
if (!start.empty()) {
|
||||
timeout = atoi(start.c_str());
|
||||
} else {
|
||||
NOTICE("bootcharting ignored\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* called to setup bootcharting */
|
||||
int bootchart_init( void )
|
||||
{
|
||||
int ret;
|
||||
char buff[4];
|
||||
int timeout = 0, count = 0;
|
||||
|
||||
buff[0] = 0;
|
||||
proc_read( LOG_STARTFILE, buff, sizeof(buff) );
|
||||
if (buff[0] != 0) {
|
||||
timeout = atoi(buff);
|
||||
}
|
||||
else {
|
||||
/* when running with emulator, androidboot.bootchart=<timeout>
|
||||
* might be passed by as kernel parameters to specify the bootchart
|
||||
* timeout. this is useful when using -wipe-data since the /data
|
||||
* partition is fresh
|
||||
*/
|
||||
char cmdline[1024];
|
||||
char* s;
|
||||
#define KERNEL_OPTION "androidboot.bootchart="
|
||||
proc_read( "/proc/cmdline", cmdline, sizeof(cmdline) );
|
||||
s = strstr(cmdline, KERNEL_OPTION);
|
||||
if (s) {
|
||||
s += sizeof(KERNEL_OPTION)-1;
|
||||
timeout = atoi(s);
|
||||
// When running with emulator, androidboot.bootchart=<timeout>
|
||||
// might be passed by as kernel parameters to specify the bootchart
|
||||
// timeout. this is useful when using -wipe-data since the /data
|
||||
// partition is fresh.
|
||||
std::string cmdline;
|
||||
android::ReadFileToString("/proc/cmdline", &cmdline);
|
||||
#define KERNEL_OPTION "androidboot.bootchart="
|
||||
if (strstr(cmdline.c_str(), KERNEL_OPTION) != NULL) {
|
||||
timeout = atoi(cmdline.c_str() + sizeof(KERNEL_OPTION) - 1);
|
||||
}
|
||||
}
|
||||
if (timeout == 0)
|
||||
|
@ -309,15 +179,25 @@ int bootchart_init( void )
|
|||
if (timeout > BOOTCHART_MAX_TIME_SEC)
|
||||
timeout = BOOTCHART_MAX_TIME_SEC;
|
||||
|
||||
count = (timeout*1000 + BOOTCHART_POLLING_MS-1)/BOOTCHART_POLLING_MS;
|
||||
int count = (timeout*1000 + BOOTCHART_POLLING_MS-1)/BOOTCHART_POLLING_MS;
|
||||
|
||||
ret = TEMP_FAILURE_RETRY(mkdir(LOG_ROOT,0755));
|
||||
log_stat = fopen(LOG_STAT, "we");
|
||||
if (log_stat == NULL) {
|
||||
return -1;
|
||||
}
|
||||
log_procs = fopen(LOG_PROCS, "we");
|
||||
if (log_procs == NULL) {
|
||||
fclose(log_stat);
|
||||
return -1;
|
||||
}
|
||||
log_disks = fopen(LOG_DISK, "we");
|
||||
if (log_disks == NULL) {
|
||||
fclose(log_stat);
|
||||
fclose(log_procs);
|
||||
return -1;
|
||||
}
|
||||
|
||||
file_buff_open(log_stat, LOG_STAT);
|
||||
file_buff_open(log_procs, LOG_PROCS);
|
||||
file_buff_open(log_disks, LOG_DISK);
|
||||
|
||||
/* create kernel process accounting file */
|
||||
// Create kernel process accounting file.
|
||||
{
|
||||
int fd = open( LOG_ACCT, O_WRONLY|O_CREAT|O_TRUNC|O_CLOEXEC,0644);
|
||||
if (fd >= 0) {
|
||||
|
@ -330,18 +210,27 @@ int bootchart_init( void )
|
|||
return count;
|
||||
}
|
||||
|
||||
static int bootchart_step( void )
|
||||
{
|
||||
int do_bootchart_init(int nargs, char** args) {
|
||||
g_remaining_samples = bootchart_init();
|
||||
if (g_remaining_samples < 0) {
|
||||
ERROR("bootcharting init failure: %s\n", strerror(errno));
|
||||
} else if (g_remaining_samples > 0) {
|
||||
NOTICE("bootcharting started (will run for %d ms)\n", g_remaining_samples*BOOTCHART_POLLING_MS);
|
||||
} else {
|
||||
NOTICE("bootcharting ignored\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bootchart_step() {
|
||||
do_log_file(log_stat, "/proc/stat");
|
||||
do_log_file(log_disks, "/proc/diskstats");
|
||||
do_log_procs(log_procs);
|
||||
|
||||
/* we stop when /data/bootchart/stop contains 1 */
|
||||
{
|
||||
char buff[2];
|
||||
if (proc_read(LOG_STOPFILE,buff,sizeof(buff)) > 0 && buff[0] == '1') {
|
||||
return -1;
|
||||
}
|
||||
// Stop if /data/bootchart/stop contains 1.
|
||||
std::string stop;
|
||||
if (android::ReadFileToString(LOG_STOPFILE, &stop) && stop == "1") {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -352,42 +241,40 @@ static long long bootchart_gettime() {
|
|||
return 10LL*get_uptime_jiffies();
|
||||
}
|
||||
|
||||
/* called each time you want to perform a bootchart sampling op */
|
||||
static void bootchart_finish() {
|
||||
unlink(LOG_STOPFILE);
|
||||
fclose(log_stat);
|
||||
fclose(log_disks);
|
||||
fclose(log_procs);
|
||||
acct(NULL);
|
||||
}
|
||||
|
||||
void bootchart_sample(int* timeout) {
|
||||
if (g_remaining_samples > 0) {
|
||||
long long current_time;
|
||||
int elapsed_time, remaining_time;
|
||||
// Do we have any more bootcharting to do?
|
||||
if (g_remaining_samples <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
current_time = bootchart_gettime();
|
||||
elapsed_time = current_time - last_bootchart_time;
|
||||
long long current_time = bootchart_gettime();
|
||||
int elapsed_time = current_time - g_last_bootchart_time;
|
||||
|
||||
if (elapsed_time >= BOOTCHART_POLLING_MS) {
|
||||
/* count missed samples */
|
||||
while (elapsed_time >= BOOTCHART_POLLING_MS) {
|
||||
elapsed_time -= BOOTCHART_POLLING_MS;
|
||||
g_remaining_samples--;
|
||||
}
|
||||
/* count may be negative, take a sample anyway */
|
||||
last_bootchart_time = current_time;
|
||||
if (bootchart_step() < 0 || g_remaining_samples <= 0) {
|
||||
bootchart_finish();
|
||||
g_remaining_samples = 0;
|
||||
}
|
||||
if (elapsed_time >= BOOTCHART_POLLING_MS) {
|
||||
/* count missed samples */
|
||||
while (elapsed_time >= BOOTCHART_POLLING_MS) {
|
||||
elapsed_time -= BOOTCHART_POLLING_MS;
|
||||
g_remaining_samples--;
|
||||
}
|
||||
if (g_remaining_samples > 0) {
|
||||
remaining_time = BOOTCHART_POLLING_MS - elapsed_time;
|
||||
if (*timeout < 0 || *timeout > remaining_time) {
|
||||
*timeout = remaining_time;
|
||||
}
|
||||
/* count may be negative, take a sample anyway */
|
||||
g_last_bootchart_time = current_time;
|
||||
if (bootchart_step() < 0 || g_remaining_samples <= 0) {
|
||||
bootchart_finish();
|
||||
g_remaining_samples = 0;
|
||||
}
|
||||
}
|
||||
if (g_remaining_samples > 0) {
|
||||
int remaining_time = BOOTCHART_POLLING_MS - elapsed_time;
|
||||
if (*timeout < 0 || *timeout > remaining_time) {
|
||||
*timeout = remaining_time;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void bootchart_finish( void )
|
||||
{
|
||||
unlink( LOG_STOPFILE );
|
||||
file_buff_done(log_stat);
|
||||
file_buff_done(log_disks);
|
||||
file_buff_done(log_procs);
|
||||
acct(NULL);
|
||||
}
|
||||
|
|
|
@ -17,8 +17,6 @@
|
|||
#ifndef _BOOTCHART_H
|
||||
#define _BOOTCHART_H
|
||||
|
||||
int bootchart_init();
|
||||
void bootchart_sample(int* timeout);
|
||||
void bootchart_finish();
|
||||
|
||||
#endif /* _BOOTCHART_H */
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
#ifndef _INIT_PROPERTY_H
|
||||
#define _INIT_PROPERTY_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <sys/system_properties.h>
|
||||
|
||||
extern void handle_property_set_fd(void);
|
||||
|
|
|
@ -110,6 +110,7 @@ class <name>
|
|||
onrestart
|
||||
Execute a Command (see below) when service restarts.
|
||||
|
||||
|
||||
Triggers
|
||||
--------
|
||||
Triggers are strings which can be used to match certain kinds
|
||||
|
@ -132,6 +133,7 @@ boot
|
|||
The above stub sets test.c to 1 only when
|
||||
both test.a=1 and test.b=1
|
||||
|
||||
|
||||
Commands
|
||||
--------
|
||||
|
||||
|
@ -283,63 +285,41 @@ init.svc.<name>
|
|||
State of a named service ("stopped", "running", "restarting")
|
||||
|
||||
|
||||
Example init.conf
|
||||
-----------------
|
||||
Bootcharting
|
||||
------------
|
||||
|
||||
# not complete -- just providing some examples of usage
|
||||
#
|
||||
on boot
|
||||
export PATH /sbin:/system/sbin:/system/bin
|
||||
export LD_LIBRARY_PATH /system/lib
|
||||
This version of init contains code to perform "bootcharting": generating log
|
||||
files that can be later processed by the tools provided by www.bootchart.org.
|
||||
|
||||
mkdir /dev
|
||||
mkdir /proc
|
||||
mkdir /sys
|
||||
On the emulator, use the new -bootchart <timeout> option to boot with
|
||||
bootcharting activated for <timeout> seconds.
|
||||
|
||||
mount tmpfs tmpfs /dev
|
||||
mkdir /dev/pts
|
||||
mkdir /dev/socket
|
||||
mount devpts devpts /dev/pts
|
||||
mount proc proc /proc
|
||||
mount sysfs sysfs /sys
|
||||
On a device, create /data/bootchart/start with a command like the following:
|
||||
|
||||
write /proc/cpu/alignment 4
|
||||
adb shell 'echo $TIMEOUT > /data/bootchart/start'
|
||||
|
||||
ifup lo
|
||||
Where the value of $TIMEOUT corresponds to the desired bootcharted period in
|
||||
seconds. Bootcharting will stop after that many seconds have elapsed.
|
||||
You can also stop the bootcharting at any moment by doing the following:
|
||||
|
||||
hostname localhost
|
||||
domainname localhost
|
||||
adb shell 'echo 1 > /data/bootchart/stop'
|
||||
|
||||
mount yaffs2 mtd@system /system
|
||||
mount yaffs2 mtd@userdata /data
|
||||
Note that /data/bootchart/stop is deleted automatically by init at the end of
|
||||
the bootcharting. This is not the case with /data/bootchart/start, so don't
|
||||
forget to delete it when you're done collecting data.
|
||||
|
||||
import /system/etc/init.conf
|
||||
The log files are written to /data/bootchart/. A script is provided to
|
||||
retrieve them and create a bootchart.tgz file that can be used with the
|
||||
bootchart command-line utility:
|
||||
|
||||
class_start default
|
||||
sudo apt-get install pybootchartgui
|
||||
$ANDROID_BUILD_TOP/system/core/init/grab-bootchart.sh
|
||||
bootchart ./bootchart.tgz
|
||||
gnome-open bootchart.png
|
||||
|
||||
service adbd /sbin/adbd
|
||||
user adb
|
||||
group adb
|
||||
|
||||
service usbd /system/bin/usbd -r
|
||||
user usbd
|
||||
group usbd
|
||||
socket usbd 666
|
||||
|
||||
service zygote /system/bin/app_process -Xzygote /system/bin --zygote
|
||||
socket zygote 666
|
||||
|
||||
service runtime /system/bin/runtime
|
||||
user system
|
||||
group system
|
||||
|
||||
service akmd /sbin/akmd
|
||||
disabled
|
||||
user akmd
|
||||
group akmd
|
||||
|
||||
Debugging notes
|
||||
---------------
|
||||
Debugging init
|
||||
--------------
|
||||
By default, programs executed by init will drop stdout and stderr into
|
||||
/dev/null. To help with debugging, you can execute your program via the
|
||||
Android program logwrapper. This will redirect stdout/stderr into the
|
||||
|
@ -350,7 +330,7 @@ service akmd /system/bin/logwrapper /sbin/akmd
|
|||
|
||||
For quicker turnaround when working on init itself, use:
|
||||
|
||||
mm
|
||||
mm -j
|
||||
m ramdisk-nodeps
|
||||
m bootimage-nodeps
|
||||
adb reboot bootloader
|
||||
|
|
Loading…
Reference in New Issue