項目基本完成,同事寫的實現方式,記錄一下,後面項目開發可以參考。
1、android\device\softwinner\t7-common\init.sun8iw17p1.rc
service logcat /system/bin/logcat -f /data/local/logcat.log -n 4 -v time -r4096 -Kklog
class main
user root
service logcat-radio /system/bin/logcat -b radio -f /data/local/logcat-radio.log -r1000 -n 4 -v time
class main
user root
service logcopyerd /system/bin/logcopyerd
class main
socket logcopyerd stream 0777 root system
user root
2、android\device\softwinner\t7-p1\etc\logger.sh
#!/system/bin/sh
FILE_PATH=/data/local/logs
FILE_PREFIX_KERNLOG=kernlog
FILE_PREFIX_MAINLOG=mainlog
FILE_PREFIX_RADIOLOG=radiolog
#sleep 30
if [ ! -d $FILE_PATH ]
then
mkdir -p $FILE_PATH
fi
rename_logfile()
{
FILE_PREFIX=$1
LAST_LAST_LAST_FILE=`busybox find $FILE_PATH/ -name "$FILE_PREFIX-*.log.last.last"`
LAST_LAST_FILE=`busybox find $FILE_PATH/ -name "$FILE_PREFIX-*.log.last"`
LAST_FILE=`busybox find $FILE_PATH/ -name "$FILE_PREFIX-*.log"`
#change log files name
echo "$LAST_LAST_LAST_FILE $LAST_LAST_FILE $LAST_FILE"
rm $LAST_LAST_LAST_FILE
mv $LAST_LAST_FILE $LAST_LAST_FILE.last
mv $LAST_FILE $LAST_FILE.last
}
logger_kmsg()
{
echo "logger $FILE_PREFIX_KERNLOG ..."
rename_logfile $FILE_PREFIX_KERNLOG
busybox cat /proc/kmsg > $FILE_PATH/$FILE_PREFIX_KERNLOG-`date +%Y%m%d-%H%M`.log
}
logger_logcat()
{
echo "logger $FILE_PREFIX_MAINLOG ..."
rename_logfile $FILE_PREFIX_MAINLOG
logcat -v time -f $FILE_PATH/$FILE_PREFIX_MAINLOG-`date +%Y%m%d-%H%M`.log
}
logger_radio()
{
echo "logger $FILE_PREFIX_RADIOLOG ..."
rename_logfile $FILE_PREFIX_RADIOLOG
logcat -v time -b radio -f $FILE_PATH/$FILE_PREFIX_RADIOLOG-`date +%Y%m%d-%H%M`.log
}
case "$1" in
kernel)
logger_kmsg;;
android)
logger_logcat;;
radio)
logger_radio;;
*)
print "error argument, only for kernel, android, radio\n"
;;
esac
3、android\device\softwinner\common\init.common.rc
#service logger_kernel /system/bin/logger.sh kernel
# user root
# disabled
# oneshot
#service logger_android /system/bin/logger.sh android
# user root
# disabled
# oneshot
#service logger_service /system/bin/log_service
# class main
# user root
# disabled
# oneshot
#service logger_private /system/bin/log_service private
# class main
# user root
# oneshot
4、t7\android\device\softwinner\t7-p1\packages.mk
PRODUCT_PACKAGES += \
com.neo.media \
......................................
logcopyerd \
logcopy.sh
5、logcopyerd和 logcopy.sh實現
t7\android\vendor\t7\NEO\services\logcopyerd\logcopyerd.c
#define LOG_TAG "logcopyerd"
#include <ctype.h>
#include <dirent.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <string.h>
#include <unistd.h>
#include <cutils/sockets.h>
#include <cutils/log.h>
#include <cutils/properties.h>
#define COPYLOG_DEBUG 0
#define PRINT_ERR(format, ...) ALOGW("%s(%d)" format, __FUNCTION__, __LINE__, ## __VA_ARGS__)
#if COPYLOG_DEBUG
#define PRINT_DBG(format, ...) ALOGW("%s(%d)" format, __FUNCTION__, __LINE__, ## __VA_ARGS__)
#else
#define PRINT_DBG(...)
#endif
#define SOCKET_PATH "logcopyerd"
#define BUFFER_MAX 1024 // input buffer for commands
#define TOKEN_MAX 30 // max number of arguments in buffer
#define COPY_ERROR_SRC_NOT_EXISTS -1 // copy error src file not exists
#define COPY_ERROR_DEST_CANNOT_OPEN -2 // copy error when dest file cannot open
#define COPY_ERROR_MKDIR -3 // copy error when mkdir
#define COPY_ERROR_SUB_MKDIR -4 // copy error when smb mkdir
#define COPY_ERROR_SIZE_NOT_EQUALS -5 // copy error size not equals
#define CMD_LIST_FILES "lsfiles"
#define CMD_COPY_FILES "cpfiles"
#define DATA_LOCAL_PATH "/data/local/"
#define RECOVERY_PATH "/cache/recovery/"
#define ANR_TRACES_PATH "/data/anr/traces.txt"
#define THERMAL_FILE "sys/devices/virtual/thermal/thermal_zone0/temp"
#define CPUFREQ_FILE "sys/devices/system/cpu/cpufreq/all_time_in_state"
#define SYSTEM_BUILD_PROC "/system/build.prop"
#define DEFAULT_BUILD_PROC "/default.prop"
#define CONFIG_MEM_INI "/config_mem.ini"
#define COPY_PROC_FILE_LIST_MAX 18
static char copy_proc_file_list[][16]={
"meminfo",
"interrupts",
"timer_list"
"crypto",
"devices",
"diskstats",
"interrupts",
"iomem",
"meminfo",
"loadavg",
"slabinfo",
"softirqs",
"stat",
"timer_list",
"version",
"vmallocinfo",
"vmstat",
"zoneinfo",
};
#define SPACE_REPLACE_CHARS ""
static int readx(int s, void *_buf, int count) {
char *buf = _buf;
int n = 0, r;
if (count < 0) {
PRINT_ERR("count < 0\n");
return -1;
}
while (n < count) {
r = read(s, buf + n, count - n);
if (r < 0) {
if (errno == EINTR){
continue;
}
PRINT_ERR("read error: %s\n", strerror(errno));
return -1;
}
if (r == 0) {
PRINT_ERR("eof\n");
return -1;
}
n += r;
}
return 0;
}
static int writex(int s, const void *_buf, int count) {
const char *buf = _buf;
int n = 0, r;
if (count < 0) {
PRINT_ERR("count < 0\n");
return -1;
}
while (n < count) {
r = write(s, buf + n, count - n);
if (r < 0) {
if (errno == EINTR) continue;
PRINT_ERR("write error: %s\n", strerror(errno));
return -1;
}
n += r;
}
return 0;
}
static int replace_str_all(char *src, char *target, char *replacement)
{
if (!src || !target) {
PRINT_ERR("src or target is null\n");
return -1;
}
unsigned short s_len, t_len, r_len, tem_len;
s_len = strlen(src);
t_len = strlen(target);
r_len = strlen(replacement);
if (t_len <= 0) {
PRINT_ERR("t_len < 0\n");
return -1;
}
tem_len = (t_len>=r_len) ? s_len : (((s_len/t_len)+1) * r_len);
char tem_str[tem_len];
unsigned short n = 0;
unsigned short tem_idx = 0;
char *_src = src, *found;
unsigned short _len, i;
while ((found = strstr(_src, target))) {
_len = (found - _src);
i = 0;
while (i < _len) {
tem_str[tem_idx++] = _src[i++];
}
i = 0;
while (i < r_len) {
tem_str[tem_idx++] = replacement[i++];
}
_src += (_len + t_len);
n++;
}
i = 0;
_len = ((src + s_len) - _src);
while (i < _len) {
tem_str[tem_idx++] = _src[i++];
}
strncpy(src, tem_str, tem_len);
src[tem_idx] = 0;
return n;
}
static int copy_file(const char *src, char *dest) {
int ret;
char cmd[256];
snprintf(cmd, 256, "%s %s %s", "/system/bin/logcopy.sh", src, dest);
PRINT_ERR("copy_file '%s'", cmd);
ret = system(cmd);
system("sync");
if (ret == 0) {
PRINT_ERR("copied file '%s'", src);
} else {
PRINT_ERR("failed to copy '%s'\n", src);
return COPY_ERROR_SIZE_NOT_EQUALS;
}
if (chmod(dest, 0766) < 0) {
PRINT_ERR("cannot chmod dir '%s': %s\n", dest, strerror(errno));
}
return 0;
}
static int do_list_files(char **arg, char *reply) {
DIR *d;
struct dirent *de;
// FILES[ f1 f2 f3 f4 ... ]SELIF
snprintf(reply, BUFFER_MAX, "%s", "FILES[");
d = opendir(DATA_LOCAL_PATH);
if (d != NULL) {
while ((de = readdir(d))) {
if (de->d_type == DT_REG) {
int _fd;
char _file[256];
struct stat _st;
snprintf(_file, 256, "%s/%s", DATA_LOCAL_PATH, de->d_name);
_fd = open(_file, O_RDONLY);
fstat(_fd, &_st);
snprintf(reply, BUFFER_MAX, "%s %s:%lld:%lu000", reply, de->d_name, _st.st_size, _st.st_mtime);
PRINT_DBG("name=%s:%lu", de->d_name, _st.st_mtime);
close(_fd);
}
}
// close opened directory
closedir(d);
}
if (!access(ANR_TRACES_PATH, 0)) {
int _fd;
struct stat _st;
_fd = open(ANR_TRACES_PATH, O_RDONLY);
fstat(_fd, &_st);
snprintf(reply, BUFFER_MAX, "%s %s:%lld:%lu000", reply, ANR_TRACES_PATH, _st.st_size, _st.st_mtime);
PRINT_DBG("name=%s:%lu", ANR_TRACES_PATH, _st.st_mtime);
close(_fd);
}
snprintf(reply, BUFFER_MAX, "%s %s", reply, "]SELIF");
PRINT_ERR("reply=%s, arg=%s", reply, arg[0]);
return 0;
}
void cmd_copy_files(char *dest_dir, char *reply)
{
int index = 0;
char cmd[BUFFER_MAX] = {0};
char other_dir[BUFFER_MAX] = {0};
char *str_error;
if (!access(dest_dir, 0)) {
PRINT_ERR("DIR '%s' is exists.", dest_dir);
} else if (mkdir(dest_dir, 0777) < 0) {
str_error = strerror(errno);
PRINT_ERR("cannot create dest_dir '%s': %s\n", dest_dir, str_error);
snprintf(reply, BUFFER_MAX, "MSG[COPY]{ [ERROR(%d:%s)]all:all }GSM", COPY_ERROR_MKDIR, str_error);
return;
}
snprintf(other_dir, BUFFER_MAX, "%s/other/", dest_dir);
if (mkdir(other_dir, 0777) < 0) {
str_error = strerror(errno);
PRINT_ERR("cannot create other_dir '%s': %s\n", other_dir, str_error);
snprintf(reply, BUFFER_MAX, "MSG[COPY]{ [ERROR(%d:%s)]all:all }GSM", COPY_ERROR_MKDIR, str_error);
return;
}
memset(cmd, 0, BUFFER_MAX);
snprintf(cmd, BUFFER_MAX, "cp %s %s", THERMAL_FILE, other_dir);
system(cmd);
memset(cmd, 0, BUFFER_MAX);
snprintf(cmd, BUFFER_MAX, "cp %s %s", CPUFREQ_FILE, other_dir);
system(cmd);
memset(cmd, 0, BUFFER_MAX);
snprintf(cmd, BUFFER_MAX, "cp %s %s", SYSTEM_BUILD_PROC, other_dir);
system(cmd);
memset(cmd, 0, BUFFER_MAX);
snprintf(cmd, BUFFER_MAX, "cp %s %s", DEFAULT_BUILD_PROC, other_dir);
system(cmd);
memset(cmd, 0, BUFFER_MAX);
snprintf(cmd, BUFFER_MAX, "cp %s %s", CONFIG_MEM_INI, other_dir);
system(cmd);
for(index=0; index<COPY_PROC_FILE_LIST_MAX; index++){
memset(cmd, 0, BUFFER_MAX);
snprintf(cmd, BUFFER_MAX, "cp /proc/%s %s", copy_proc_file_list[index], other_dir);
system(cmd);
}
memset(cmd, 0, BUFFER_MAX);
snprintf(cmd, BUFFER_MAX, "cp -R %s/* %s", DATA_LOCAL_PATH, dest_dir);
system(cmd);
memset(cmd, 0, BUFFER_MAX);
snprintf(cmd, BUFFER_MAX, "cp -R %s/* %s", RECOVERY_PATH, dest_dir);
system(cmd);
memset(cmd, 0, BUFFER_MAX);
snprintf(cmd, BUFFER_MAX, "cp %s %s", ANR_TRACES_PATH, dest_dir);
system(cmd);
system("sync");
snprintf(reply, BUFFER_MAX, "MSG[SUCCESS]{}GSM");
PRINT_ERR(" dest_dir=%s reply=%s cmd=%s", dest_dir, reply, cmd);
}
static int execute(int s, char *cmd) {
char *arg[TOKEN_MAX + 1];
unsigned short n = 0;
unsigned short count;
// n is number of args (not counting arg[0])
arg[0] = cmd;
PRINT_ERR("execute=%s, cmdLen=%d", cmd, sizeof(cmd));
while (*cmd) {
if (isspace(*cmd)) {
*cmd++ = 0;
n++;
arg[n] = cmd;
if (n == TOKEN_MAX) {
PRINT_ERR("Too many arguments for [%s]", arg[0]);
goto DONE;
}
}
cmd++;
}
char reply[BUFFER_MAX];
if (!strncmp(CMD_LIST_FILES, arg[0], strlen(CMD_LIST_FILES))) {
PRINT_ERR("CMD_LIST_FILES");
snprintf(reply, BUFFER_MAX, "dmesg > %s/kernel.log", DATA_LOCAL_PATH);
system(reply);
memset(reply, 0, BUFFER_MAX);
do_list_files(arg + 1, reply);
} else if (!strncmp(CMD_COPY_FILES, arg[0], strlen(CMD_COPY_FILES))) {
PRINT_ERR("CMD_COPY_FILES");
cmd_copy_files(arg[1], reply);
}
DONE:{
if (!reply[0]) {
snprintf(reply, BUFFER_MAX, "%s", "MSG[]{}GSM");
}
// write length & reply
count = strlen(reply);
if (writex(s, &count, sizeof(count))) {
PRINT_ERR("writex is error");
return -1;
}
if (writex(s, reply, count)) {
PRINT_ERR("writex is error");
return -1;
}
}
return 0;
}
int main(const int argc, const char *argv[]) {
char buf[BUFFER_MAX];
struct sockaddr addr;
socklen_t alen;
int lsocket, s, count;
PRINT_ERR("argc=%d, argv=%s\n", argc, argv[0]);
lsocket = android_get_control_socket(SOCKET_PATH);
if (lsocket < 0) {
PRINT_ERR("Failed to get socket from environment: %s\n", strerror(errno));
exit(1);
}
if (listen(lsocket, 5)) {
PRINT_ERR("Listen on socket failed: %s\n", strerror(errno));
exit(1);
}
fcntl(lsocket, F_SETFD, FD_CLOEXEC);
for (;;) {
alen = sizeof(addr);
PRINT_ERR("1 get socket from environment: %s\n", SOCKET_PATH);
s = accept(lsocket, &addr, &alen);// 等待客戶端請求連接
PRINT_ERR("2 get socket from environment: %s\n", SOCKET_PATH);
if (s < 0) {
ALOGE("Accept failed: %s\n", strerror(errno));
continue;
}
fcntl(s, F_SETFD, FD_CLOEXEC);
PRINT_ERR("new connection\n");
for (;;) {
unsigned short count;
if (readx(s, &count, sizeof(count))) {
PRINT_ERR("failed to read size\n");
break;
}
if ((count < 1) || (count >= BUFFER_MAX)) {
PRINT_ERR("invalid size %d\n", count);
break;
}
if (readx(s, buf, count)) {
PRINT_ERR("failed to read command\n");
break;
}
buf[count] = 0;
if (execute(s, buf)) {
PRINT_ERR("execute\n");
break;
}
}
PRINT_ERR("closing connection\n");
close(s);
}
return 0;
}
t7\android\vendor\t7\NEO\services\logcopyerd\Android.mk
LOCAL_PATH := $(call my-dir)
# build logcopyerd
include $(CLEAR_VARS)
LOCAL_SRC_FILES := logcopyerd.c
LOCAL_SHARED_LIBRARIES := libcutils
LOCAL_MODULE := logcopyerd
LOCAL_MODULE_TAGS := optional
include $(BUILD_EXECUTABLE)
# build logcopy.sh
include $(CLEAR_VARS)
LOCAL_MODULE := logcopy.sh
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_CLASS := EXECUTABLES
LOCAL_SRC_FILES := $(LOCAL_MODULE)
include $(BUILD_PREBUILT)
#include $(CLEAR_VARS)
#LOCAL_MODULE_TAGS := optional eng debug user
#LOCAL_MODULE := logcopy.sh
#LOCAL_SRC_FILES := logcopy.sh
#LOCAL_MODULE_CLASS := EXECUTABLES
# We don't need any additional suffix.
#LOCAL_MODULE_SUFFIX :=
#include $(BUILD_PREBUILT)
t7\android\vendor\t7\NEO\services\logcopyerd\logcopy.sh
#!/system/bin/busybox ash
src=$1
dest=$2
/system/bin/busybox cp -rf ${src} ${dest}
/system/bin/busybox sync
6、APP層實現:
上層APP與logcopyerd服務之間是通過套接字接口建立數據通信的,如下:
t7\android\vendor\t7\NEO\frameworks\base\java\com\neo\util\LogCopyer.java
private static final String SOCKET_NAME_LOGCOPYER = "logcopyerd";
private boolean connect() {
if (mSocket != null) {
return true;
}
Log.d(TAG, "1 Connecting... sockey name:" + SOCKET_NAME_LOGCOPYER);
try {
mSocket = new LocalSocket();
Log.d(TAG, "2 Connecting... mIn=" + mIn + ", mOut=" + mOut);
mSocket.connect(new LocalSocketAddress(SOCKET_NAME_LOGCOPYER,
LocalSocketAddress.Namespace.RESERVED));// 客戶端請求連接
Log.d(TAG, "3 Connected... 如果這裏沒有打印,socket沒有建立,可能是權限問題, 修改init.rc文件");
mIn = mSocket.getInputStream(); //建立輸入和輸出
mOut = mSocket.getOutputStream(); //建立輸入輸出
} catch (IOException ex) {
disconnect();
return false;
}
return true;
}
private void disconnect() {
Log.i(TAG, "disconnecting... sockey name:" + SOCKET_NAME_LOGCOPYER);
try {
if (mSocket != null)
mSocket.close();
} catch (IOException ex) {
}
try {
if (mIn != null)
mIn.close();
} catch (IOException ex) {
}
try {
if (mOut != null)
mOut.close();
} catch (IOException ex) {
}
mSocket = null;
mIn = null;
mOut = null;
}
private boolean readBytes(byte buffer[], int len) {
int off = 0, count;
if (len < 0)
return false;
while (off != len) {
try {
count = mIn.read(buffer, off, len - off); //套接字接口輸入讀出
if (count <= 0) {
Log.e(TAG, "read error " + count);
break;
}
off += count;
} catch (IOException ex) {
Log.e(TAG, "read exception");
break;
}
}
Log.d(TAG, "read " + len + " bytes");
if (off == len)
return true;
disconnect();
return false;
}
private boolean readReply() {
int len;
mBufferLen = 0;
if (!readBytes(mBuffer, 2))
return false;
len = (((int) mBuffer[0]) & 0xff) | ((((int) mBuffer[1]) & 0xff) << 8);
if ((len < 1) || (len > 1024)) {
Log.e(TAG, "invalid reply length (" + len + ")");
disconnect();
return false;
}
if (!readBytes(mBuffer, len))
return false;
mBufferLen = len;
return true;
}
private boolean writeCommand(String _cmd) {
byte[] cmd = _cmd.getBytes();
int len = cmd.length;
if ((len < 1) || (len > 1024))
return false;
mBuffer[0] = (byte) (len & 0xff);
mBuffer[1] = (byte) ((len >> 8) & 0xff);
try {
mOut.write(mBuffer, 0, 2); //套接字輸出接口向緩衝寫數據
mOut.write(cmd, 0, len);
} catch (IOException ex) {
Log.e(TAG, "write error");
disconnect();
return false;
}
return true;
}
private synchronized boolean transaction(String cmd) {
Log.d(TAG, "transaction() cmd: " + cmd);
if (!connect()) {
Log.e(TAG, "connection failed");
return false;
}
if (!writeCommand(cmd)) {
// Try again.
if (!connect() || !writeCommand(cmd)) {
return false;
}
}
Log.d(TAG, "send: '" + cmd + "'");
if (!readReply()) {
Log.d(TAG, "fail");
return false;
}
return true;
}
private boolean execute(String cmd) {
return transaction(cmd);
}