全志平臺android日誌信息打印到SD卡中的實現方法

項目基本完成,同事寫的實現方式,記錄一下,後面項目開發可以參考。

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);
	}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章