vendor/qcom/opensource: testframework enhancements and bug fixes
1)moving testframework to qcom specific opensource
2)new shell introduced for improving usability in collecting events
3)fixed to stop kenel tracing when tracing stopped by userspace command
diff --git a/Android.mk b/Android.mk
new file mode 100644
index 0000000..a648c58
--- /dev/null
+++ b/Android.mk
@@ -0,0 +1,45 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+ifdef TARGET_USES_TESTFRAMEWORK
+#testframework lib
+LOCAL_PRELINK_MODULE := false
+LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)
+LOCAL_SRC_FILES := \
+ src/TestFrameworkApi.cpp \
+ src/TestFrameworkCommon.cpp \
+ src/TestFrameworkHash.cpp \
+ src/TestFramework.cpp \
+ src/TestFrameworkService.cpp
+
+LOCAL_CFLAGS := -DCUSTOM_EVENTS_TESTFRAMEWORK
+
+LOCAL_C_INCLUDES := $(TOP)/vendor/qcom/opensource/testframework
+
+LOCAL_SHARED_LIBRARIES += \
+ libutils \
+ libcutils \
+ libbinder
+
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE:= libtestframework
+include $(BUILD_SHARED_LIBRARY)
+
+#testframework servcice
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ src/TestFrameworkServiceMain.cpp \
+ src/TFSShell.cpp
+
+LOCAL_C_INCLUDES := vendor/qcom/opensource/testframework
+
+LOCAL_SHARED_LIBRARIES := libtestframework libcutils libutils libbinder
+
+LOCAL_CFLAGS := -DCUSTOM_EVENTS_TESTFRAMEWORK
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE:= testframeworkservice
+
+include $(BUILD_EXECUTABLE)
+
+endif
diff --git a/inc/testframework.h b/inc/testframework.h
new file mode 100644
index 0000000..523d683
--- /dev/null
+++ b/inc/testframework.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of Code Aurora Forum, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ANDROID_TEST_FRAMEWORK_H
+#define ANDROID_TEST_FRAMEWORK_H
+
+#include <stdarg.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define TF_EVENT_ID_SIZE_MAX 32
+
+enum {
+ TF_EVENT_START = 0x01,
+ TF_EVENT_STOP = 0x02,
+ TF_EVENT = 0x04,
+ TF_EVENT_JAVA_START = 0x08,
+ TF_EVENT_JAVA_STOP = 0x10,
+ TF_EVENT_JAVA = 0x20,
+};
+
+//logging type
+enum {
+ TF_DISABLE,
+ TF_TESTFRAMEWORK,
+ TF_LOGCAT,
+ TF_LOGCAT_FTRACE,
+ TF_ALL,
+};
+
+#if defined CUSTOM_EVENTS_TESTFRAMEWORK || defined GFX_TESTFRAMEWORK
+#define CONDITION(cond) (__builtin_expect((cond)!=0, 0))
+
+#define TF_WRITE(buf) tf_write(buf)
+#define TF_PRINT(eventtype, eventgrp, eventid, ...) \
+ tf_print(eventtype, eventgrp, eventid, __VA_ARGS__)
+
+#define TF_WRITE_IF(cond, buf) \
+ ( (CONDITION(cond)) \
+ ? TF_WRITE(buf) \
+ : (void)0 )
+
+#define TF_PRINT_IF(cond, eventtype, eventgrp, eventid, ...) \
+ ( (CONDITION(cond)) \
+ ? TF_PRINT(eventtype, eventgrp, eventid, __VA_ARGS__) \
+ : (void)0 )
+#define TF_TURNON() tf_turnon()
+#define TF_TURNOFF() tf_turnoff()
+
+int tf_write(const char *buf);
+int tf_print(int eventtype, const char *eventgrp,
+ const char *eventid, const char *fmt, ...);
+int tf_turnon();
+int tf_turnoff();
+
+#else
+
+#define TF_WRITE(...) ((void)0)
+#define TF_PRINT(...) ((void)0)
+#define TF_WRITE_IF(...) ((void)0)
+#define TF_PRINT_IF(...) ((void)0)
+#define TF_TURNON() ((void)0)
+#define TF_TURNOFF() ((void)0)
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // ANDROID_TEST_FRAMEWORK_H
diff --git a/src/TFSShell.cpp b/src/TFSShell.cpp
new file mode 100644
index 0000000..70ff980
--- /dev/null
+++ b/src/TFSShell.cpp
@@ -0,0 +1,649 @@
+/*
+ * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of Code Aurora Forum, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdint.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mount.h>
+#include <sys/uio.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <utils/Errors.h>
+#include <utils/threads.h>
+#include <utils/CallStack.h>
+#include <utils/Log.h>
+#include <cutils/properties.h>
+#include <cutils/atomic.h>
+#include <binder/IServiceManager.h>
+#include <utils/String16.h>
+#include <binder/Parcel.h>
+#include <binder/IPCThreadState.h>
+#include <binder/ProcessState.h>
+#include "TestFrameworkService.h"
+#include "TFSShell.h"
+
+#define TFS_VERSION "TF v2.0"
+#define PROMPT "\n>>>"
+#define MAX_FILTERLEN 64
+#define TFS_MIN(x, y) ((x) < (y))?(x):(y)
+
+TFSShell::TFSShell() {
+ mBuf = (char *) malloc(sizeof(char) * MAX_BUFLEN);
+ mPath = (char *) malloc(sizeof(char) * MAX_PATHLEN);
+ if(mPath) {
+ mPath[0] = '/';
+ mPath[1] = '\0';
+ }
+ mService = NULL;
+}
+
+TFSShell::~TFSShell() {
+ if(mBuf) {
+ free(mBuf);
+ mBuf = NULL;
+ }
+ if(mPath) {
+ free(mPath);
+ mPath = NULL;
+ }
+}
+
+int TFSShell::MainLoop(ITestFrameworkService *service) {
+ char *cmds = NULL;
+ bool quit = false;
+ char *arg = NULL;
+ FILE *fp = NULL;
+ int ret = -1;
+ int n = 0, fd = -1, fd2 = -1;
+ int len = 0, arglen = 0;
+ int total = 0;
+
+ if(!mBuf) {
+ return -1;
+ }
+
+ mService = service;
+
+ cmds = (char *) malloc(sizeof(char) * MAX_PATHLEN);
+
+ while(!quit) {
+ TFSTtyPrint(PROMPT);
+ ret = -1;
+ fgets(mBuf, MAX_BUFLEN, stdin);
+ arglen = strlen(mBuf);
+ if(arglen > 0 && mBuf[arglen-1] == '\n') {
+ mBuf[arglen-1] = '\0';
+ }
+ arg = TFSGetCmdArg(mBuf, arglen);
+ switch(mBuf[0]) {
+ case 'h':
+ case 'H':
+ //help
+ if(arglen != 4 || strncmp(mBuf, "help", 4)) {
+ break;
+ }
+
+ TFSCmdHint("help");
+ ret = 0;
+ break;
+
+ case 'v':
+ case 'V':
+ TFSTtyPrint(TFS_VERSION);
+ ret = 0;
+ break;
+
+ case 'e':
+ case 'E':
+ //exit
+ if(arglen == 4 && !strncmp(mBuf, "exit", 4)) {
+ property_set("debug.tf.exit", "1");
+ quit = true;
+ ret = 0;
+ }
+ else if(arglen == 9 && !strncmp(mBuf, "eventtype", 9)) {
+ arg = TFSGetCmdArg(arg+arglen, arglen);
+ //eventtype <type>
+ if(arg) {
+ arg[arglen] = '\0';
+ property_set("debug.tf.eventtype", arg);
+ }
+ else {
+ property_get("debug.tf.eventtype", mBuf, "0");
+ TFSTtyPrint(mBuf, strlen(mBuf));
+ }
+ ret = 0;
+ }
+ break;
+
+ case 'k':
+ if(arglen != 8 || strncmp(mBuf, "kfilters", 4)) {
+ break;
+ }
+ //kfilters [available|list|set <filters>]
+ //filters := !|+<subsystem>:<event>
+ arg = TFSGetCmdArg(arg+arglen, arglen);
+ if(NULL == arg) {
+ //list
+ fd = open(NODE_STR(set_event), O_RDONLY);
+ while ((n = read(fd, mBuf, MAX_BUFLEN)) > 0) {
+ mBuf[n-1] = '\0';
+ TFSTtyPrint(mBuf, n);
+ }
+ close(fd);
+ }
+ else if(arg[0] == 'l') {
+ //list
+ fd = open(NODE_STR(set_event), O_RDONLY);
+ while ((n = read(fd, mBuf, MAX_BUFLEN)) > 0) {
+ mBuf[n-1] = '\0';
+ TFSTtyPrint(mBuf, n);
+ }
+ close(fd);
+ }
+ else if(arg[0] == 's') {
+ //set <filters>
+ arg = TFSGetCmdArg(arg+arglen, arglen);
+ if(arg) {
+ char filter[MAX_FILTERLEN];
+ if(arg[0] == '+') {
+ arg = TFSGetCmdArg(arg+1, arglen);
+ fd = open(NODE_STR(set_event), O_WRONLY);
+ }
+ else {
+ fd = open(NODE_STR(set_event), O_WRONLY|O_TRUNC);
+ }
+ if(arg) {
+ arg[arglen] = '\0';
+ }
+ arg = TFSGetFilterArg(arg, arglen);
+ while(arg) {
+ strlcpy(filter, arg, TFS_MIN(arglen+1, MAX_FILTERLEN));
+ n = write(fd, filter, arglen);
+ arg = TFSGetFilterArg(arg+arglen, arglen);
+ }
+ close(fd);
+ }
+ else {
+ //empty filters
+ fd = open(NODE_STR(set_event), O_WRONLY|O_TRUNC);
+ close(fd);
+ }
+ }
+ else if(arg[0] == 'a') {
+ //available events
+ fd = open(NODE_STR(available_events), O_RDONLY);
+ while ((n = read(fd, mBuf, MAX_BUFLEN)) > 0) {
+ mBuf[n-1] = '\0';
+ TFSTtyPrint(mBuf, n);
+ }
+ close(fd);
+ }
+ else {
+ TFSCmdHint("kfilters");
+ }
+ ret = 0;
+ break;
+
+ case 'f':
+ if(arglen != 7 || strncmp(mBuf, "filters", 7)) {
+ break;
+ }
+ //filters [available|list|set <filters>]
+ arg = TFSGetCmdArg(arg+arglen, arglen);
+ if(NULL == arg) {
+ property_get("debug.tf.filters", mBuf, "");
+ TFSTtyPrint(mBuf, strlen(mBuf));
+ }
+ else if(arg[0] == 's' || arg[0] == 's') {
+ //ufilters [available|list|set <filters>]
+ //filters := !|+<subsystem>:<event>
+ bool bRemove = false;
+ arg = (char *) TFSGetCmdArg(arg+arglen, arglen);
+ if(arg) {
+ char filters[MAX_FILTERLEN];
+ char * str = NULL;
+ filters[0] = '\0';
+ if(arg[0] == '+') {
+ arg = (char *)TFSGetCmdArg(arg+1, arglen);
+ if(arg) {
+ arg[arglen] = '\0';
+ }
+ property_get("debug.tf.filters", filters, NULL);
+ arg = TFSGetFilterArg(arg, arglen);
+ while(arg) {
+ bRemove = false;
+ arg[arglen] = '\0';
+ if (arg[0] == '!') {
+ arg++;
+ arglen--;
+ bRemove = true;
+ }
+ str = strstr(filters, arg);
+ if (str) {
+ if (bRemove) {
+ if ((filters < str) && (*(str-1) == '%'))
+ strlcpy(str-1, str+arglen, MAX_FILTERLEN - (str - filters));
+ else if(filters+strlen(filters) > str+arglen && *(str+arglen) == '%') {
+ strlcpy(str, str+arglen+1, MAX_FILTERLEN - (str - filters));
+ }
+ else
+ strlcpy(str, str+arglen, MAX_FILTERLEN);
+ }
+ }
+ else if (!bRemove) {
+ if (filters[0] != '\0')
+ strlcat(filters, "%", MAX_FILTERLEN);
+ strlcat(filters, arg, MAX_FILTERLEN);
+ }
+ arg = TFSGetFilterArg(arg+arglen+1, arglen);
+ }
+ }
+ else {
+ arg[arglen] = '\0';
+ filters[0] = '\0';
+ arg = TFSGetFilterArg(arg, arglen);
+ while(arg) {
+ arg[arglen] = '\0';
+ if (arg[0] == '!') {
+ arg++;
+ arglen--;
+ }
+ else {
+ str = strstr(filters, arg);
+ if (!str) {
+ if (filters[0] != '\0')
+ strlcat(filters, "%", MAX_FILTERLEN);
+ strlcat(filters, arg, MAX_FILTERLEN);
+ }
+ }
+ arg = TFSGetFilterArg(arg+arglen+1, arglen);
+ }
+ }
+ property_set("debug.tf.filters", filters);
+ }
+ else {
+ property_set("debug.tf.filters", "$.$");
+ }
+ }
+ else if(arg[0] == 'l') {
+ property_get("debug.tf.filters", mBuf, "");
+ TFSTtyPrint(mBuf, strlen(mBuf));
+ }
+ else if(arg[0] == 'a') {
+ //not supported yet
+ property_get("debug.tf.filters", mBuf, "");
+ TFSTtyPrint(mBuf, strlen(mBuf));
+ }
+ else {
+ TFSCmdHint("filters");
+ }
+ ret = 0;
+ break;
+
+ case 's':
+ if(!strncmp(mBuf, "start", 5)) {
+ //start
+ arg = TFSGetCmdArg(arg+arglen, arglen);
+ if(arg && (arg[0] == 'l' || arg[0] == 'L'))
+ property_set("debug.tf.enable", "logcat");
+ else if(arg && (arg[0] == '+'))
+ property_set("debug.tf.enable", "1");
+ else if(!arg) {
+ fd = open(NODE_STR(trace), O_WRONLY|O_TRUNC);
+ close(fd);
+ property_set("debug.tf.enable", "1");
+ }
+ else
+ TFSCmdHint("start");
+
+ if(mService) {
+ mService->TFSUpdate(START);
+ }
+ ret = 0;
+ }
+ else if(!strncmp(mBuf, "stop", 4)) {
+ //stop
+ property_set("debug.tf.enable", "0");
+ if(mService) {
+ mService->TFSUpdate(STOP);
+ }
+ ret = 0;
+ }
+ else if(!strncmp(mBuf, "size", 4)) {
+ //size
+ arg = TFSGetCmdArg(arg+arglen, arglen);
+ if(arg) {
+ arg[arglen] = '\0';
+ fd = open(NODE_STR(buffer_size_kb), O_WRONLY|O_TRUNC);
+ n = write(fd, arg, arglen);
+ close(fd);
+ }
+ else {
+ fd = open(NODE_STR(buffer_size_kb), O_RDONLY);
+ n = read(fd, mBuf, MAX_BUFLEN);
+ mBuf[n-1] = '\0';
+ TFSTtyPrint(mBuf, n);
+ close(fd);
+ }
+ ret = 0;
+ }
+ break;
+
+ case 'd':
+ if(arglen != 4 || strncmp(mBuf, "dump", 4)) {
+ break;
+ }
+
+ total = 0;
+
+ //dump [path]
+ arg = TFSGetCmdArg(arg+arglen, arglen);
+
+ if(arg && !strncmp("clear", arg, 5) && (arglen == 5)) {
+ fd = open(NODE_STR(trace), O_WRONLY|O_TRUNC);
+ close(fd);
+ ret = 0;
+ break;
+ }
+
+ if(NULL != arg) {
+ arg[arglen] = '\0';
+ if(mPath) {
+ chdir(mPath);
+ }
+ fd2 = open(arg, O_WRONLY|O_CREAT|O_TRUNC,
+ S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
+ }
+
+ fd = open(NODE_STR(trace), O_RDONLY);
+ while ((n = read(fd, mBuf, MAX_BUFLEN)) > 0) {
+ if(NULL == arg) {
+ TFSTtyPrint(mBuf, n);
+ }
+ else {
+ if(fd2 >= 0) {
+ write(fd2, mBuf, n);
+ total += n;
+ }
+ else {
+ TFSTtyPrint("could not dump into file");
+ break;
+ }
+ }
+ }
+
+ if(fd2 >= 0) {
+ snprintf(mBuf, MAX_BUFLEN, "written %d bytes...\n", total);
+ TFSTtyPrint(mBuf);
+ }
+
+ close(fd);
+ close(fd2);
+ fd2 = -1;
+ ret = 0;
+ break;
+
+ case 'c':
+ if(!strncmp(mBuf, "cd", 2) && arglen==2 && mPath && cmds) {
+ arg = TFSGetCmdArg(arg+arglen, arglen);
+ if(arg) {
+ arg[arglen] = '\0';
+ snprintf(cmds, MAX_PATHLEN, "cd %s;cd %s;pwd", mPath, arg);
+ fp = popen(cmds, "r");
+ if(fp) {
+ while ( fgets( mPath, MAX_PATHLEN, fp));
+ pclose(fp);
+ }
+ int l = strlen(mPath);
+ mPath[l-1] = '\0';
+ }
+ ret = 0;
+ }
+ break;
+
+ case 'p':
+ if(!strncmp(mBuf, "pwd", 3) && arglen==3 && mPath) {
+ TFSTtyPrint(mPath);
+ ret = 0;
+ }
+ break;
+
+ case '\n':
+ ret = 0;
+ break;
+
+ default:
+ break;
+ }
+
+ if(ret < 0 && mPath && cmds) {
+ snprintf(cmds, MAX_PATHLEN, "cd %s;%s", mPath, mBuf);
+ fp = popen(cmds, "r");
+ if(fp) {
+ while ( fgets( mBuf, MAX_BUFLEN, fp)) {
+ TFSTtyPrint(mBuf);
+ }
+ pclose(fp);
+ }
+ }
+ }
+
+ if(cmds) {
+ free(cmds);
+ cmds = NULL;
+ }
+
+ return 0;
+}
+
+
+int TFSShell::TFSTtyPrint(const char *buf, int len) {
+ int ret = 0;
+
+ if(buf) {
+ if(!len) {
+ len = strlen(buf);
+ }
+ ret = write(STDOUT_FILENO, buf, len);
+ }
+
+ return ret;
+}
+
+char *TFSShell::TFSGetCmdArg(char *buf, int &len)
+{
+ char *start = buf;
+ int n = 0;
+ char *end = NULL;
+
+ len = 0;
+ if (!buf) {
+ return NULL;
+ }
+
+ n = strlen(buf);
+ end = start + n;
+
+ while (start && (start < end)) {
+ if (*start == ' ' || *start == '\t' || ( *start == '\r' ||
+ *start == '\n' || *start == '\"'))
+ ++start;
+ else
+ break;
+ }
+
+ buf = start;
+
+ while (start && (start < end)) {
+ if (*start == ' ' || *start == '\t' || ( *start == '\r' ||
+ *start == '\n' || *start == '\"')) {
+ break;
+ }
+ ++len;
+ ++start;
+ }
+
+ if(!len && start >= end) {
+ len = 0;
+ return NULL;
+ }
+ return buf;
+}
+
+char *TFSShell::TFSGetFilterArg(char *buf, int &len)
+{
+ char *start = buf;
+ int n = 0;
+ char *end = NULL;
+
+ len = 0;
+ if (!buf) {
+ return NULL;
+ }
+
+ n = strlen(buf);
+ end = start + n;
+
+ if(*start == '%') {
+ start++;
+ }
+ buf = start;
+
+ while (start && (start < end))
+ {
+ if (*start == '%') {
+ break;
+ }
+ ++len;
+ ++start;
+ }
+
+ if(!len && start >= end) {
+ len = 0;
+ return NULL;
+ }
+ return buf;
+}
+
+void TFSShell::TFSCmdHelp() {
+ TFSCmdHint("filters");
+ TFSCmdHint("kfilters");
+ TFSCmdHint("start");
+ TFSCmdHint("stop");
+ TFSCmdHint("dump");
+ TFSCmdHint("eventtype");
+ TFSCmdHint("version");
+ TFSCmdHint("exit");
+}
+
+void TFSShell::TFSCmdHint(const char *buf) {
+
+ switch(buf[0]) {
+ case 'h':
+ case 'H':
+ TFSCmdHelp();
+ break;
+ case 'd':
+ TFSTtyPrint("dump [clear|<logfile>] : dumps log\n"
+ " 'clear' - clears log\n"
+ " '<logfile>' - dumps trace log to this file\n\n");
+ break;
+ case 'v':
+ TFSTtyPrint("version : prints version number\n\n");
+ break;
+ case 'e':
+ if(buf[1] == 'v') {
+ TFSTtyPrint("eventtype [<type>] : displays (in decimal) current eventtypes allowed\n"
+ " <type> event type in decimal\n"
+ " TF_EVENT_START = 0x01\n"
+ " TF_EVENT_STOP = 0x02\n"
+ " TF_EVENT = 0x04\n"
+ " TF_EVENT_JAVA_START = 0x08\n"
+ " TF_EVENT_JAVA_STOP = 0x10\n"
+ " TF_EVENT_JAVA = 0x20\n\n");
+ }
+ else if(buf[1] == 'x') {
+ TFSTtyPrint("exit] : exit\n\n");
+ }
+
+ break;
+
+ case 's':
+ if(buf[2] == 'a') {
+ TFSTtyPrint("start [+|logcat] : starts tracing and clears previous log\n"
+ " '+' - previous log not cleared,\n"
+ " appendeds to previous log\n"
+ " 'logcat' - output redirected to logcat\n\n");
+ }
+ else if(buf[2] == 'o') {
+ TFSTtyPrint("stop : stops tracing\n\n");
+ }
+ else if(buf[1] == 'i') {
+ TFSTtyPrint("size [<size-in-kb>] : displays current buffer size\n"
+ " <size-in-kb> sets to this size\n\n");
+ }
+ break;
+ case 'f':
+ TFSTtyPrint("filters [set [<uspacefilters>]|available|list] : userspace filters\n"
+ " 'set' - clears filters \n"
+ " 'set <uspacefilters>' - sets filters \n"
+ " <uspacefilters> := [+]<filters> \n"
+ " <filters> := <filter>{%<filter>} \n"
+ " <filter> := [!]<subsystem>:<event>\n"
+ " ex: filters set SF:*%STC:* all SF, STC events set\n"
+ " filters set +Display:* - all Display events\n"
+ " added to previous filters\n"
+ " filters set +ui:*%!STC:* - all STC events removed,\n"
+ " all ui events added\n"
+ " 'available' - all available events\n"
+ " 'list' - lists all set events\n\n");
+ break;
+ case 'k':
+ TFSTtyPrint("kfilters [set [<kspacefilters>]|available|list] : kernel filters\n"
+ " 'set' - clears filters \n"
+ " 'set <kspacefilters>' - sets filters \n"
+ " <kspacefilters> := [+]<filters> \n"
+ " <filters> := <filter>{%<filter>} \n"
+ " <filter> := [!]<subsystem>:<event>\n"
+ " ex: filters set power:*%irq:* sets all power, irq events\n"
+ " filters set +sched:* - all scheduler events\n"
+ " added to previous filters\n"
+ " filters set +kgsl:*%!power:* - all power events removed,\n"
+ " all kgsl events added\n"
+ " 'available' - all available events\n"
+ " 'list' - lists all set events\n\n");
+ break;
+
+ }
+
+}
+
diff --git a/src/TFSShell.h b/src/TFSShell.h
new file mode 100644
index 0000000..d325d0f
--- /dev/null
+++ b/src/TFSShell.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of Code Aurora Forum, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+class ITestFrameworkService;
+
+class TFSShell
+{
+public:
+ TFSShell();
+ ~TFSShell();
+
+ int MainLoop(ITestFrameworkService *service);
+ static int TFSTtyPrint(const char *buf, int len = 0);
+
+private:
+ char *TFSGetCmdArg(char *buf, int &len);
+ char *TFSGetFilterArg(char *buf, int &len);
+ static void *TFSSync(void *s);
+ void TFSCmdHint(const char *cmd);
+ void TFSCmdHelp();
+
+private:
+ static const int MAX_PATHLEN = 1024;
+ static const int MAX_BUFLEN = 8192;
+
+ char *mPath;
+ char *mBuf;
+ ITestFrameworkService *mService;
+};
+
diff --git a/src/TestFramework.cpp b/src/TestFramework.cpp
new file mode 100644
index 0000000..0933c53
--- /dev/null
+++ b/src/TestFramework.cpp
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of Code Aurora Forum, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define LOG_TAG "TestFramework"
+
+#include <stdint.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mount.h>
+#include <sys/uio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <utils/Errors.h>
+#include <utils/threads.h>
+#include <utils/CallStack.h>
+#include <utils/Log.h>
+#include <cutils/properties.h>
+#include <cutils/atomic.h>
+#include <binder/IServiceManager.h>
+#include <utils/String16.h>
+#include <binder/Parcel.h>
+#include <inc/testframework.h>
+#include "TestFramework.h"
+#include "TestFrameworkService.h"
+
+const android::String16 ITestFramework::descriptor(TESTFRAMEWORK_NAME);
+const android::String16& ITestFramework::getInterfaceDescriptor() const {
+ return ITestFramework::descriptor;
+}
+
+android::sp<ITestFramework> ITestFramework::asInterface(
+ const android::sp<android::IBinder>& obj)
+{
+ android::sp<ITestFramework> intr;
+ if (obj != NULL) {
+ intr = static_cast<ITestFramework*>(
+ obj->queryLocalInterface(ITestFramework::descriptor).get());
+ if (intr == NULL) {
+ intr = new BpTestFramework(obj);
+ }
+ }
+ return intr;
+}
+ITestFramework::ITestFramework() { }
+ITestFramework::~ITestFramework() { }
+
+bool BpTestFramework::tfConnected = false;
+bool BpTestFramework::tfConnectedAgain = false;
+
+int BpTestFramework::Connect(sp<ITestFramework> &tfDispacther) {
+ if (tfConnected)
+ {
+ return 0;
+ }
+
+ android::sp<android::IServiceManager> sm = android::defaultServiceManager();
+ android::sp<android::IBinder> binder = 0;
+
+ if (sm != 0) {
+ binder = sm->checkService(android::String16(TESTFRAMEWORK_NAME));
+ }
+
+ if (binder != 0)
+ {
+ tfDispacther = android::interface_cast<ITestFramework>(binder);
+ tfConnected = true;
+ tfConnectedAgain = true;
+ return 1;
+ }
+
+ return 0;
+}
+
+void BpTestFramework::ConnectReset() {
+ tfConnected = false;
+ tfConnectedAgain = false;
+}
+
+bool BpTestFramework::IsConnectedAgain() {
+ bool ret = tfConnectedAgain;
+ tfConnectedAgain = false;
+ return ret;
+}
+
+bool BpTestFramework::DispatchMsg(const char *str) {
+ Parcel data, reply;
+ data.writeInterfaceToken(ITestFrameworkService::descriptor);
+ data.writeCString(str);
+ remote()->transact(TF_WRITE_BUF, data, &reply, IBinder::FLAG_ONEWAY);
+ return (reply.readInt32() != 0);
+}
+
+bool BpTestFramework::DispatchMsg(int val, const char *str) {
+ Parcel data, reply;
+ data.writeInterfaceToken(ITestFrameworkService::descriptor);
+ data.writeInt32(val);
+ data.writeCString(str);
+ remote()->transact(TF_WRITE_FMT_MSG, data, &reply, IBinder::FLAG_ONEWAY);
+ return (reply.readInt32() != 0);
+}
+
+void BpTestFramework::DispatchTurnOff() {
+ Parcel data, reply;
+ data.writeInterfaceToken(ITestFrameworkService::descriptor);
+ data.writeInt32(0);
+ remote()->transact(TF_TURNOFF, data, &reply, IBinder::FLAG_ONEWAY);
+}
+
+void BpTestFramework::DispatchTurnOn(int loggingtype) {
+ Parcel data, reply;
+ data.writeInterfaceToken(ITestFrameworkService::descriptor);
+ data.writeInt32(loggingtype);
+ remote()->transact(TF_TURNON, data, &reply, IBinder::FLAG_ONEWAY);
+}
+
+int BpTestFramework::DispatchGetInfo(int &w, int &x, int &y, int &z) {
+ Parcel data, reply;
+ data.writeInterfaceToken(ITestFrameworkService::descriptor);
+ remote()->transact(TF_INFO, data, &reply);
+ w = reply.readInt32();
+ x = reply.readInt32();
+ y = reply.readInt32();
+ z = reply.readInt32();
+ return 0;
+}
diff --git a/src/TestFramework.h b/src/TestFramework.h
new file mode 100644
index 0000000..0a99225
--- /dev/null
+++ b/src/TestFramework.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of Code Aurora Forum, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _TESTFRAMEWORK_H_
+#define _TESTFRAMEWORK_H_
+
+#include <utils/KeyedVector.h>
+#include <utils/RefBase.h>
+#include <utils/String16.h>
+#include <utils/threads.h>
+#include <string.h>
+#include <binder/IInterface.h>
+#include <binder/Parcel.h>
+#include <utils/Log.h>
+
+//Interface for client
+#define TESTFRAMEWORK_NAME "TestFrameworkService.TestFrameworkInterface"
+
+using namespace android;
+
+enum {
+ TF_WRITE_BUF = 1,
+ TF_WRITE_FMT_MSG = 2,
+ TF_INFO = 3,
+ TF_TURNON = 4,
+ TF_TURNOFF = 5,
+};
+
+class ITestFramework: public IInterface
+{
+public:
+ DECLARE_META_INTERFACE(TestFramework) // no trailing ;
+ virtual bool DispatchMsg(const char *str) = 0;
+ virtual bool DispatchMsg(int val, const char *str) = 0;
+ virtual void DispatchTurnOff() = 0;
+ virtual void DispatchTurnOn(int loggingtype) = 0;
+ virtual int DispatchGetInfo(int &w, int &x, int &y, int &z) = 0;
+
+ virtual void ConnectReset() = 0;
+ virtual bool IsConnectedAgain() = 0;
+};
+
+class BpTestFramework: public BpInterface<ITestFramework>
+{
+public:
+ BpTestFramework(const sp<IBinder>& impl)
+ : BpInterface<ITestFramework>(impl) {
+ tfConnected = false;
+ }
+
+ virtual bool DispatchMsg(const char *str);
+ virtual bool DispatchMsg(int val, const char *str);
+ virtual void DispatchTurnOff();
+ virtual void DispatchTurnOn(int loggingtype);
+ virtual int DispatchGetInfo(int &w, int &x, int &y, int &z);
+
+ static int Connect(sp<ITestFramework> &tfDispacther);
+ void ConnectReset();
+ bool IsConnectedAgain();
+
+private:
+ static bool tfConnected;
+ static bool tfConnectedAgain;
+};
+
+#endif
diff --git a/src/TestFrameworkApi.cpp b/src/TestFrameworkApi.cpp
new file mode 100644
index 0000000..3797266
--- /dev/null
+++ b/src/TestFrameworkApi.cpp
@@ -0,0 +1,337 @@
+/*
+ * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of Code Aurora Forum, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define LOG_TAG "TestFrameworkApi"
+
+#include <stdint.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mount.h>
+#include <sys/uio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdarg.h>
+#include <utils/Errors.h>
+#include <utils/threads.h>
+#include <utils/CallStack.h>
+#include <utils/Log.h>
+#include <cutils/properties.h>
+#include <cutils/atomic.h>
+#include <binder/IServiceManager.h>
+#include <utils/String16.h>
+#include <binder/Parcel.h>
+#include <inc/testframework.h>
+#include "TestFramework.h"
+#include "TestFrameworkCommon.h"
+#include <utils/Singleton.h>
+
+#define TF_LOG_BUF_SIZE 768
+
+class TestFrameworkClient: public TestFrameworkCommon, public Singleton<TestFrameworkClient> {
+public:
+ TestFrameworkClient();
+ ~TestFrameworkClient();
+
+ int tf_turnon();
+ int tf_turnoff();
+ int tf_write(const char *buf);
+ int tf_print(int eventtype, const char *eventgrp,
+ const char *eventid, const char *fmt, va_list ap);
+private:
+ int tf_logging_status();
+ const char *tf_get_str_eventtype(int event);
+
+private:
+ android::sp<ITestFramework> mTfDispacther;
+ int tfTs;
+};
+
+ANDROID_SINGLETON_STATIC_INSTANCE(TestFrameworkClient) ;
+
+static TestFrameworkClient &tfApi = TestFrameworkClient::getInstance();
+
+//implementation of TF APIs
+int tf_turnon() {
+ return tfApi.tf_turnon();
+}
+
+int tf_turnoff() {
+ return tfApi.tf_turnoff();
+}
+
+int tf_write(const char *buf) {
+ return tfApi.tf_write(buf);
+}
+
+int tf_print(int eventtype, const char *eventgrp,
+ const char *eventid, const char *fmt, ...) {
+ int ret = 0;
+ va_list ap;
+ va_start (ap, fmt);
+ ret = tfApi.tf_print(eventtype,eventgrp,eventid,fmt, ap);
+ va_end (ap);
+ return ret;
+}
+
+//implementation testframeworkclient
+TestFrameworkClient::TestFrameworkClient() {
+ mTfDispacther = NULL;
+ tfTs = -(TF_EXCHANGE_INTERVAL);
+}
+
+TestFrameworkClient::~TestFrameworkClient() {
+ mTfDispacther = NULL;
+}
+
+int TestFrameworkClient::tf_turnon()
+{
+ int ret = 0;
+
+ if (TfIsServiceRunning()) {
+ BpTestFramework::Connect(mTfDispacther);
+ if (mTfDispacther != 0) {
+ mTfDispacther->DispatchTurnOn(TF_TESTFRAMEWORK);
+ }
+ }
+ else {
+ if (!TfIsValid()) {
+ TfTracersInit();
+ }
+ TfUpdate(TF_TESTFRAMEWORK);
+ mTurnOnByApi = true;
+ }
+
+ return ret;
+}
+
+int TestFrameworkClient::tf_turnoff()
+{
+ int ret = 0;
+ if (TfIsServiceRunning()) {
+ if (mTfDispacther != 0) {
+ mTfDispacther->DispatchTurnOff();
+ }
+ }
+ else {
+ mTurnOnByApi = false;
+ TfUpdate(TF_DISABLE);
+ }
+ return ret;
+}
+
+int TestFrameworkClient::tf_write(const char *buf)
+{
+ int ret = 0, status = 0;
+ bool send = false;
+
+ status = tf_logging_status();
+
+ switch(status) {
+ case TF_LOGCAT:
+ __android_log_write(ANDROID_LOG_ERROR, LOG_TAG, buf);
+ break;
+ case TF_TESTFRAMEWORK:
+ case TF_ALL:
+ send = true;
+ break;
+ case TF_DISABLE:
+ break;
+ }
+
+ if (send) {
+#ifdef TF_FEATURE_MSGS_THROUGH_BINDER
+ mTfDispacther->DispatchMsg(buf);
+#else
+ ret = TfWrite(buf);
+#endif
+ }
+
+ return ret;
+}
+
+int TestFrameworkClient::tf_print(int eventtype, const char *eventgrp,
+ const char *eventid, const char *fmt, va_list ap) {
+ char evarg[TF_LOG_BUF_SIZE];
+ int ret = 0, idx=0, status = TF_DISABLE;
+ bool send = false;
+
+ status = tf_logging_status();
+
+ if (TF_DISABLE == status ||
+ !(mEventType & eventtype) ||
+ !TfSearchFilterInTable(eventgrp, eventid) ||
+ !IsTraceGatesOpen()) {
+ return 0;
+ }
+
+ switch(status) {
+ case TF_LOGCAT: {
+ __android_log_vprint(ANDROID_LOG_ERROR, eventgrp, fmt, ap);
+ }
+ break;
+ case TF_LOGCAT_FTRACE:
+ break;
+ case TF_TESTFRAMEWORK: {
+ char modifiedEventID[TF_EVENT_ID_SIZE_MAX];
+
+ if (!TfIsValid()) {
+ TfTracersInit();
+ }
+
+ //add pid to eve
+ snprintf(modifiedEventID, TF_EVENT_ID_SIZE_MAX, "%s-%d", eventid, getpid());
+ snprintf(evarg, TF_LOG_BUF_SIZE, "name=%s [class=%s, info=", modifiedEventID, eventgrp);
+ idx = strlen(evarg);
+ vsnprintf (evarg+idx, TF_LOG_BUF_SIZE-idx, fmt, ap);
+ idx = strlen(evarg);
+ snprintf (evarg+idx, TF_LOG_BUF_SIZE-idx, " {%s}", tf_get_str_eventtype(eventtype));
+ idx = strlen(evarg);
+ if (idx < TF_LOG_BUF_SIZE-2) {
+ strlcpy(evarg+idx, "]\n", TF_LOG_BUF_SIZE-idx);
+ }
+ send = true;
+ }
+ break;
+ case TF_ALL: {
+ char modifiedEventID[TF_EVENT_ID_SIZE_MAX];
+
+ if (!TfIsValid()) {
+ TfTracersInit();
+ }
+
+ //add pid to events
+ snprintf(modifiedEventID, TF_EVENT_ID_SIZE_MAX, "%s-%d", eventid, getpid());
+ __android_log_vprint(ANDROID_LOG_ERROR, eventgrp, fmt, ap);
+ snprintf(evarg, TF_LOG_BUF_SIZE, "name=%s [class=%s, info=", modifiedEventID, eventgrp);
+ idx = strlen(evarg);
+ vsnprintf (evarg+idx, TF_LOG_BUF_SIZE-idx, fmt, ap);
+ idx = strlen(evarg);
+ snprintf (evarg+idx, TF_LOG_BUF_SIZE-idx, " {%s}", tf_get_str_eventtype(eventtype));
+ idx = strlen(evarg);
+ if (idx < TF_LOG_BUF_SIZE-2) {
+ strlcpy(evarg+idx, "]\n", TF_LOG_BUF_SIZE-idx);
+ }
+ send = true;
+ }
+ break;
+ case TF_DISABLE:
+ default:
+ break;
+ }
+
+
+ if (send) {
+#ifdef TF_FEATURE_MSGS_THROUGH_BINDER
+ if (mTfDispacther != 0) {
+ mTfDispacther->DispatchMsg(eventtype, evarg);
+ }
+#else
+ ret = TfWrite(eventtype, evarg);
+#endif
+ }
+
+ return ret;
+}
+
+int TestFrameworkClient::tf_logging_status() {
+ int status = TF_DISABLE, time_now = 0;
+ bool timeout = 0;
+
+ //probe frequency set to 1, so lets not probe
+ //any params whatever set initially they will be used
+ if (mProbeFreq <= 1) {
+ return mLogType;
+ }
+
+ time_now = ns2ms(systemTime());
+ timeout = (time_now - tfTs >= mProbeFreq);
+
+ //eventhough binder doesn't incur much overhead, lets not use it
+ //everytime, one in few milliseconds fetch data from tf service
+ if (timeout) {
+ if (TfIsServiceRunning()) {
+ BpTestFramework::Connect(mTfDispacther);
+
+ if (mTfDispacther != 0) {
+ mTfDispacther->DispatchGetInfo(mLogType, mEventType,
+ mOpenInterval, mClosedInterval);
+
+ if (!mEventType) {
+ mTfDispacther->ConnectReset();
+ }
+
+ if ((mLogType != TF_DISABLE) && mTfDispacther->IsConnectedAgain()) {
+ TfGetPropertyFilters();
+ }
+ }
+ }
+ else {
+ TfUpdate();
+ if (mLogType != TF_DISABLE) {
+ TfGetPropertyFilters();
+ }
+ }
+ status = mLogType;
+ tfTs = time_now;
+ }
+ else {
+ status = mLogType;
+ }
+
+ return status;
+}
+
+const char *TestFrameworkClient::tf_get_str_eventtype(int event) {
+ const char *str = "";
+ switch(event) {
+ case TF_EVENT_START:
+ str = "TF_EVENT_START";
+ break;
+ case TF_EVENT_STOP:
+ str = "TF_EVENT_STOP";
+ break;
+ case TF_EVENT:
+ str = "TF_EVENT";
+ break;
+ case TF_EVENT_JAVA_START:
+ str = "TF_EVENT_JAVA_START";
+ break;
+ case TF_EVENT_JAVA_STOP:
+ str = "TF_EVENT_JAVA_STOP";
+ break;
+ case TF_EVENT_JAVA:
+ str = "TF_EVENT_JAVA";
+ break;
+ default:
+ break;
+ }
+ return str;
+}
diff --git a/src/TestFrameworkCommon.cpp b/src/TestFrameworkCommon.cpp
new file mode 100644
index 0000000..14c182e
--- /dev/null
+++ b/src/TestFrameworkCommon.cpp
@@ -0,0 +1,516 @@
+/*
+ * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of Code Aurora Forum, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define LOG_TAG "TestFrameworkCommon"
+
+#include <stdint.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mount.h>
+#include <sys/uio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <utils/Errors.h>
+#include <utils/threads.h>
+#include <utils/CallStack.h>
+#include <utils/Log.h>
+#include <cutils/properties.h>
+#include <cutils/atomic.h>
+#include <binder/IServiceManager.h>
+#include <utils/String16.h>
+#include <binder/Parcel.h>
+#include <binder/IPCThreadState.h>
+#include <binder/ProcessState.h>
+#include <inc/testframework.h>
+#include "TestFramework.h"
+#include "TestFrameworkService.h"
+#include "TestFrameworkHash.h"
+
+#define _STR(x) #x
+#define STR(x) _STR(x)
+
+TestFrameworkCommon::TestFrameworkCommon() {
+ LOGD("TestFrameworkCommon created");
+ mTfInitDone = false;
+ mTfTracerFd = -1;
+ mTfMarkerFd = -1;
+ mLogType = TF_DISABLE;
+ mDebugfsFound = 0;
+ mFilterTable = NULL;
+ mElapsedTime = 0;
+ mLastRecordedTime = ns2ms(systemTime());
+ mEventType = TF_EVENT | TF_EVENT_START | TF_EVENT_STOP |
+ TF_EVENT_JAVA | TF_EVENT_JAVA_START | TF_EVENT_JAVA_STOP;
+ mClosedInterval = 0;
+ mOpenInterval = 0;
+ mIsService = 1;
+ mProbeFreq = TF_EXCHANGE_INTERVAL;
+ mFilters[0] = '\0';
+ mFiltersLen = 0;
+ mTurnOnByApi = false;
+
+ TfInit();
+}
+
+TestFrameworkCommon::~TestFrameworkCommon() {
+ if (mFilterTable) {
+ delete mFilterTable;
+ mFilterTable = NULL;
+ }
+}
+
+int TestFrameworkCommon::TfWrite(const char *str) {
+ int ret = 0;
+
+ if (mTfMarkerFd < 0) {
+ return -1;
+ }
+
+ if (str) {
+ ret = ::write(mTfMarkerFd, str, strlen(str));
+ }
+
+ return ret;
+}
+
+
+int TestFrameworkCommon::TfWrite(int evType, const char *evArg) {
+ struct iovec iov[2];
+ char evid[TF_EVENT_ID_SIZE_MAX];
+ int num, ret = 0;
+
+ if (mTfMarkerFd < 0) {
+ return -1;
+ }
+
+ iov[0].iov_base = (void *) evArg;
+ iov[0].iov_len = strlen(evArg)+1;
+
+ switch(evType)
+ {
+ case TF_EVENT_START:
+ strlcpy(evid, "uspace_start", sizeof(evid));
+ break;
+ case TF_EVENT_STOP:
+ strlcpy(evid, "uspace_stop", sizeof(evid));
+ break;
+ case TF_EVENT:
+ strlcpy(evid, "uspace_single", sizeof(evid));
+ break;
+ case TF_EVENT_JAVA_START:
+ strlcpy(evid, "uspace_start", sizeof(evid));
+ break;
+ case TF_EVENT_JAVA_STOP:
+ strlcpy(evid, "uspace_stop", sizeof(evid));
+ break;
+ case TF_EVENT_JAVA:
+ strlcpy(evid, "uspace_single", sizeof(evid));
+ break;
+ default:
+ evid[0] = '\0';
+ }
+
+ num = 2;
+ iov[1].iov_base = (void *) evid;
+ iov[1].iov_len = strlen(evid)+1;
+
+ if (evArg) {
+ ret = writev(mTfMarkerFd, iov, num);
+ }
+
+ return ret;
+}
+
+int TestFrameworkCommon::TfInit() {
+ if (NULL == mFilterTable) {
+ mFilterTable = new TfHashTable(256, (HashFreeFunc) free,
+ (HashCompareFunc) strcmp,
+ (HashCompute) TfHashTable::ComputeUtf8Hash);
+ }
+
+ mIsService = !(0 == TfGetPropertyService());
+ mProbeFreq = TfGetPropertyProbeFreq();
+
+ return 0;
+}
+
+int TestFrameworkCommon::TfTracersInit() {
+ char *debugfs;
+ char path[MAX_PATH];
+
+ if (mTfInitDone) {
+ return 0;
+ }
+
+ //open tracing/tracing_on
+ if (mTfTracerFd < 0) {
+ TfOpenTracer();
+ }
+
+ //open tracing/trace_marker
+ if (mTfMarkerFd < 0) {
+ TfOpenMarker();
+ }
+
+ if (mTfTracerFd >= 0 && mTfMarkerFd >= 0) {
+ mTfInitDone = true;
+ }
+
+ return 0;
+}
+
+void TestFrameworkCommon::TfEnable() {
+ if (mTfTracerFd >= 0) {
+ lseek(mTfTracerFd, 0, SEEK_SET);
+ write(mTfTracerFd, "1", 1);
+ LOGD("TfEnable");
+ }
+ else {
+ LOGE("tf_turnon: could not open trace file");
+ }
+}
+
+void TestFrameworkCommon::TfDisable() {
+ if (mTfTracerFd >= 0) {
+ lseek(mTfTracerFd, 0, SEEK_SET);
+ write(mTfTracerFd, "0", 1);
+ LOGD("TfDisable");
+ }
+ else {
+ LOGE("tf_turnoff: could not open trace file");
+ }
+}
+
+void TestFrameworkCommon::TfUpdate(int logtype, int updatetype) {
+
+ if (updatetype != SYNC || !mTurnOnByApi) {
+ mLogType = logtype;
+ if (logtype < 0) {
+ mLogType = TfGetPropertyLogType();
+ }
+ }
+
+ if (updatetype != SYNC && mTurnOnByApi) {
+ //start, stop commands can close api turned on logging
+ mTurnOnByApi = false;
+ }
+
+ if (mLogType != TF_DISABLE) {
+ mEventType = TfGetPropertyEventType();
+ TfGetPropertyTraceGatesInterval(mOpenInterval, mClosedInterval);
+ }
+
+ if (((mLogType == TF_ALL) || (mLogType == TF_TESTFRAMEWORK)) &&
+ !TfIsTracerEnabled()) {
+ TfEnable();
+ }
+ else if (((mLogType != TF_ALL) && (mLogType != TF_TESTFRAMEWORK)) &&
+ TfIsTracerEnabled()) {
+ TfDisable();
+ }
+ return;
+}
+
+int TestFrameworkCommon::TfGetPropertyService() {
+ char property[PROPERTY_VALUE_MAX];
+ int service = 0;
+
+ if (property_get("debug.tf.service", property, "0") > 0) {
+ service = atoi(property);
+ }
+ return service;
+}
+
+int TestFrameworkCommon::TfGetPropertyProbeFreq() {
+ char property[PROPERTY_VALUE_MAX];
+ int period = 0;
+
+ if (property_get("debug.tf.probeperiod", property, "1000") > 0) {
+ period = atoi(property);
+ }
+ return period;
+}
+
+//usage:
+//setprop debug.testframework.enable logcat - logs to logcat only
+//setprop debug.testframework.enable tf - logs to testframework
+//setprop debug.testframework.enable testframework - logs to tf only
+//setprop debug.testframework.enable all - logs to logcat and tf
+//setprop debug.testframework.enable * - logs to logcat and tf
+int TestFrameworkCommon::TfGetPropertyLogType() {
+ int status = TF_DISABLE;
+ char property[PROPERTY_VALUE_MAX];
+
+ if (property_get("debug.tf.enable", property, "0") > 0) {
+ switch(property[0]) {
+ case 'L':
+ case 'l':
+ status = TF_LOGCAT;
+ break;
+ case 'T':
+ case 't':
+ case '1':
+ status = TF_TESTFRAMEWORK;
+ break;
+ case '*':
+ case 'a':
+ case 'A':
+ status = TF_ALL;
+ break;
+ case 'd':
+ case 'D':
+ case '0':
+ default:
+ status = TF_DISABLE;
+ break;
+ }
+ }
+
+ return status;
+}
+
+int TestFrameworkCommon::TfGetPropertyFilters() {
+ char property[PROPERTY_VALUE_MAX];
+ char key[PROPERTY_VALUE_MAX];
+ char *tptr = NULL, *sptr = NULL, *eptr = NULL;
+ int len = 0;
+
+ if (property_get("debug.tf.filters", property, "*:*") > 0) {
+ sptr = property;
+ len = strlen(property);
+ eptr = sptr + len;
+
+ if (mFiltersLen != len || strcmp(mFilters, property)) {
+ strlcpy(mFilters, property, sizeof(mFilters));
+ mFiltersLen = len;
+ //clear table
+ if (mFilterTable) {
+ mFilterTable->TfHashTableClear();
+ }
+
+ do {
+ tptr = strchr(sptr, '%');
+ if (!tptr && sptr < eptr) {
+ tptr = eptr;
+ }
+ if(tptr) {
+ strncpy(key, sptr, tptr-sptr);
+ key[tptr-sptr] = '\0';
+ //don't bother about duplicate entries, hashtable
+ //will take care of them
+ TfAddFilterToTable(key);
+ sptr = tptr+1;
+ }
+ } while(tptr && sptr < eptr);
+ }
+ }
+ return 0;
+}
+
+int TestFrameworkCommon::TfGetPropertyEventType() {
+ int status = TF_EVENT | TF_EVENT_STOP;
+ char property[PROPERTY_VALUE_MAX];
+
+ if (property_get("debug.tf.eventtype", property, "255") > 0) {
+ status = atoi(property);
+ }
+
+ return status;
+}
+
+void TestFrameworkCommon::TfGetPropertyTraceGatesInterval(int &openInterval,
+ int &closeInterval) {
+ int interval = 1;
+ char property[PROPERTY_VALUE_MAX];
+ char *tptr = NULL;
+
+ if (property_get("debug.tf.interval", property, "0 0") > 0) {
+ tptr = strchr(property, ' ');
+ if (tptr) {
+ mClosedInterval = atoi(tptr+1);
+ *tptr = '\0';
+ mOpenInterval = atoi(property);
+ }
+ }
+ return;
+}
+
+bool TestFrameworkCommon::TfIsTracerEnabled() {
+ bool ret = false;
+ int n = 0;
+ char buf[1];
+ buf[0] = 0;
+ if (mTfTracerFd) {
+ lseek(mTfTracerFd, 0, SEEK_SET);
+ n = read(mTfTracerFd, buf, 1);
+ if ((n > 0) && (buf[0] == '1')) {
+ ret = true;
+ }
+ }
+
+ return ret;
+}
+
+bool TestFrameworkCommon::TfIsValid() {
+ return mTfInitDone;
+}
+
+bool TestFrameworkCommon::TfIsServiceRunning() {
+ return mIsService;
+}
+
+int TestFrameworkCommon::TfGetLoggingType() {
+ return mLogType;
+}
+
+const char *TestFrameworkCommon::TfFindDebugfs(void) {
+ char type[100];
+ FILE *fp;
+
+ if (mDebugfsFound)
+ return mDebugfs;
+
+ if ((fp = fopen("/proc/mounts","r")) == NULL)
+ return NULL;
+
+ while (fscanf(fp, "%*s %"
+ STR(MAX_PATH)
+ "s %99s %*s %*d %*d\n",
+ mDebugfs, type) == 2) {
+ if (strcmp(type, "debugfs") == 0)
+ break;
+ }
+ fclose(fp);
+
+ if (strcmp(type, "debugfs") != 0)
+ return NULL;
+
+ mDebugfsFound = 1;
+
+ return mDebugfs;
+ }
+
+int TestFrameworkCommon::TfMountDebugfs(void) {
+ int ret = 0;
+
+ ret = ::mount("nodev", "/sys/kernel/debug", "debugfs", MS_MGC_VAL, "");
+ return ret;
+}
+
+int TestFrameworkCommon::TfOpenMarker() {
+ char *debugfs;
+ char path[MAX_PATH];
+
+ //TfMountDebugfs();
+ debugfs = (char *) TfFindDebugfs();
+
+ if (debugfs) {
+ strlcpy(path, debugfs, sizeof(path));
+ strlcat(path, "/tracing/trace_marker", sizeof(path));
+ errno = 0;
+ mTfMarkerFd = open(path, O_WRONLY);
+ LOGV("tf_marker opened=%d", mTfMarkerFd);
+ }
+
+ return mTfMarkerFd;
+}
+
+int TestFrameworkCommon::TfOpenTracer() {
+ char *debugfs;
+ char path[MAX_PATH];
+
+ //TfMountDebugfs();
+ debugfs = (char *) TfFindDebugfs();
+
+ if (debugfs) {
+ strlcpy(path, debugfs, sizeof(path));
+ strlcat(path, "/tracing/tracing_on", sizeof(path));
+ errno = 0;
+ mTfTracerFd = open(path, O_RDWR);
+ LOGV("tf_tracer opened=%d", mTfTracerFd);
+ }
+
+ return mTfTracerFd;
+}
+
+void TestFrameworkCommon::TfAddFilterToTable(const char *key) {
+ if (mFilterTable) {
+ mFilterTable->TfHashTableLookup((void *)key, strlen(key)+1, true);
+ }
+}
+
+bool TestFrameworkCommon::TfSearchFilterInTable(const char *eventgrp,
+ const char *eventid) {
+ char key[128];
+ const char* ent = NULL;
+
+ if (mFilterTable) {
+ snprintf(key, 128, "%s:%s", eventgrp, eventid);
+ ent = (const char *) mFilterTable->TfHashTableLookup(key);
+ if (ent == NULL) {
+ snprintf(key, 128, "%s:*", eventgrp);
+ ent = (const char *) mFilterTable->TfHashTableLookup(key);
+ if (ent == NULL) {
+ strlcpy(key, "*:*", 128);
+ ent = (const char *) mFilterTable->TfHashTableLookup(key);
+ if (ent == NULL) {
+ strlcpy(key, "*.*", 128);
+ ent = (const char *) mFilterTable->TfHashTableLookup(key);
+ }
+ }
+ }
+ }
+
+ return (ent != NULL);
+}
+
+bool TestFrameworkCommon::IsTraceGatesOpen() {
+ static bool bClosed = false;
+ int time_now = ns2ms(systemTime());
+ mElapsedTime += (time_now - mLastRecordedTime);
+ mLastRecordedTime = time_now;
+ bool timeout = true;
+ if(bClosed) {
+ timeout = (!mClosedInterval || (mElapsedTime >= mClosedInterval));
+ if (timeout) {
+ bClosed = false;
+ mElapsedTime = 0;
+ }
+ }
+ else {
+ bClosed = (mOpenInterval && (mElapsedTime >= mOpenInterval));
+ if (bClosed) {
+ mElapsedTime = 0;
+ }
+ }
+ return timeout;
+}
+
diff --git a/src/TestFrameworkCommon.h b/src/TestFrameworkCommon.h
new file mode 100644
index 0000000..032c39d
--- /dev/null
+++ b/src/TestFrameworkCommon.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of Code Aurora Forum, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _TESTFRAMEWORKCOMMON_H_
+#define _TESTFRAMEWORKCOMMON_H_
+
+#include <utils/KeyedVector.h>
+#include <utils/RefBase.h>
+#include <utils/String16.h>
+#include <utils/threads.h>
+#include <string.h>
+#include <binder/IInterface.h>
+#include <binder/Parcel.h>
+#include <utils/Log.h>
+
+using namespace android;
+
+#define TF_EVENT_ID_SIZE_MAX 32
+#define MAX_PATH 256
+#define TF_EXCHANGE_INTERVAL 1000
+
+class TfHashTable;
+
+//update types
+enum {
+ START,
+ STOP,
+ SYNC
+};
+
+class TestFrameworkCommon {
+public:
+ TestFrameworkCommon();
+ ~TestFrameworkCommon();
+
+ int TfInit();
+ int TfTracersInit();
+ void TfUpdate(int logtype = -1, int updatetype = SYNC);
+ int TfOpenMarker();
+ int TfOpenTracer();
+ int TfGetLoggingType();
+ bool TfIsValid();
+ bool TfIsServiceRunning();
+ int TfWrite(const char *str);
+ int TfWrite(int evType, const char *evArg);
+
+ bool TfSearchFilterInTable(const char *eventgrp, const char *eventid);
+ int TfGetPropertyService();
+ int TfGetPropertyProbeFreq();
+ int TfGetPropertyFilters();
+ int TfGetPropertyLogType();
+ int TfGetPropertyEventType();
+ void TfGetPropertyTraceGatesInterval(int &openInterval,
+ int &closeInterval);
+ bool IsTraceGatesOpen();
+protected:
+ const char *TfFindDebugfs(void);
+ int TfMountDebugfs(void);
+ bool TfIsTracerEnabled();
+ void TfEnable();
+ void TfDisable();
+ void TfAddFilterToTable(const char *key);
+
+protected:
+ bool mTfInitDone;
+ int mTfTracerFd;
+ int mTfMarkerFd;
+
+ char mDebugfs[MAX_PATH+1];
+ int mDebugfsFound;
+
+ TfHashTable *mFilterTable;
+
+ int mElapsedTime;
+ int mLastRecordedTime;
+
+ int mLogType;
+ int mEventType;
+ int mClosedInterval;
+ int mOpenInterval;
+
+ bool mIsService;
+
+ int mProbeFreq;
+
+ char mFilters[PROPERTY_VALUE_MAX];
+ int mFiltersLen;
+
+ bool mTurnOnByApi;
+};
+
+#endif
diff --git a/src/TestFrameworkHash.cpp b/src/TestFrameworkHash.cpp
new file mode 100644
index 0000000..5d944a5
--- /dev/null
+++ b/src/TestFrameworkHash.cpp
@@ -0,0 +1,310 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ * Copyright (c) 2012 Code Aurora Forum. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/*
+ * Hash table. The dominant calls are add and lookup, with removals
+ * happening very infrequently. We use probing, and don't worry much
+ * about tombstone removal.
+ */
+#define LOG_TAG "TestFrameworkHash"
+
+#include <stdlib.h>
+#include <utils/Log.h>
+#include "TestFrameworkHash.h"
+
+/* table load factor, i.e. how full can it get before we resize */
+//#define LOAD_NUMER 3 // 75%
+//#define LOAD_DENOM 4
+#define LOAD_NUMER 5 // 62.5%
+#define LOAD_DENOM 8
+//#define LOAD_NUMER 1 // 50%
+//#define LOAD_DENOM 2
+
+/*
+ * Create and initialize a hash table.
+ */
+TfHashTable::TfHashTable(size_t initialSize, HashFreeFunc freeFunc,
+ HashCompareFunc cmpFunc, HashCompute computeFunc)
+{
+ pEntries = NULL;
+ numEntries = numDeadEntries = 0;
+ pthread_mutex_init(&lock, NULL);
+
+ if (initialSize <= 0) {
+ return;
+ }
+
+ initialSize = TfHashSize(initialSize);
+ tableSize = roundUpPower2(initialSize);
+ this->freeFunc = freeFunc;
+ this->cmpFunc = cmpFunc;
+ this->computeFunc = computeFunc;
+ pEntries = (HashEntry*) malloc(tableSize * sizeof(HashEntry));
+ if (pEntries == NULL) {
+ return;
+ }
+
+ memset(pEntries, 0, tableSize * sizeof(HashEntry));
+}
+
+/*
+ * Free the table.
+ */
+TfHashTable::~TfHashTable()
+{
+ TfHashTableClear();
+ free(pEntries);
+}
+
+/*
+ * Clear out all entries.
+ */
+void TfHashTable::TfHashTableClear()
+{
+ HashEntry* pEnt;
+ int i;
+
+ TfHashTableLock();
+ pEnt = pEntries;
+ for (i = 0; i < tableSize; i++, pEnt++) {
+ if (pEnt->data == HASH_TOMBSTONE) {
+ // nuke entry
+ pEnt->data = NULL;
+ } else if (pEnt->data != NULL) {
+ // call free func then nuke entry
+ if (freeFunc != NULL)
+ (*freeFunc)(pEnt->data);
+ pEnt->data = NULL;
+ }
+ }
+
+ numEntries = 0;
+ numDeadEntries = 0;
+ TfHashTableUnlock();
+}
+
+/*
+ * Compute the capacity needed for a table to hold "size" elements.
+ */
+size_t TfHashTable::TfHashSize(size_t size) {
+ return (size * LOAD_DENOM) / LOAD_NUMER +1;
+}
+
+/*
+ * Resize a hash table. We do this when adding an entry increased the
+ * size of the table beyond its comfy limit.
+ *
+ * This essentially requires re-inserting all elements into the new storage.
+ *
+ * If multiple threads can access the hash table, the table's lock should
+ * have been grabbed before issuing the "lookup+add" call that led to the
+ * resize, so we don't have a synchronization problem here.
+ */
+bool TfHashTable::resizeHash(int newSize)
+{
+ HashEntry* pNewEntries;
+ int i;
+
+ if (countTombStones() != numDeadEntries)
+ return false;
+
+ pNewEntries = (HashEntry*) calloc(newSize, sizeof(HashEntry));
+ if (pNewEntries == NULL)
+ return false;
+
+ for (i = 0; i < tableSize; i++) {
+ void* data = pEntries[i].data;
+ if (data != NULL && data != HASH_TOMBSTONE) {
+ int hashValue = pEntries[i].hashValue;
+ int newIdx;
+
+ /* probe for new spot, wrapping around */
+ newIdx = hashValue & (newSize-1);
+ while (pNewEntries[newIdx].data != NULL)
+ newIdx = (newIdx + 1) & (newSize-1);
+
+ pNewEntries[newIdx].hashValue = hashValue;
+ pNewEntries[newIdx].data = data;
+ }
+ }
+
+ free(pEntries);
+ pEntries = pNewEntries;
+ tableSize = newSize;
+ numDeadEntries = 0;
+
+ if(countTombStones() != 0)
+ return false;
+
+ return true;
+}
+
+/*
+ * Look up an entry.
+ *
+ * We probe on collisions, wrapping around the table.
+ */
+void* TfHashTable::TfHashTableLookup(void* item, int len, bool doAdd)
+{
+ HashEntry* pEntry;
+ HashEntry* pEnd;
+ void* result = NULL;
+
+ if ((tableSize <= 0) || (item == HASH_TOMBSTONE) || (item == NULL))
+ return NULL;
+
+ unsigned int itemHash = 0;
+
+ if (computeFunc) {
+ itemHash = (*computeFunc)(item);
+ }
+
+ TfHashTableLock();
+ /* jump to the first entry and probe for a match */
+ pEntry = &pEntries[itemHash & (tableSize-1)];
+ pEnd = &pEntries[tableSize];
+ while (pEntry->data != NULL) {
+ if (pEntry->data != HASH_TOMBSTONE &&
+ pEntry->hashValue == itemHash &&
+ (*cmpFunc)(pEntry->data, item) == 0)
+ {
+ /* match */
+ break;
+ }
+
+ pEntry++;
+ if (pEntry == pEnd) { /* wrap around to start */
+ if (tableSize == 1)
+ break; /* edge case - single-entry table */
+ pEntry = pEntries;
+ }
+ }
+
+ if (pEntry->data == NULL) {
+ if (doAdd) {
+ pEntry->hashValue = itemHash;
+ pEntry->data = malloc(len);
+ if (pEntry->data != NULL) {
+ memmove(pEntry->data, item, len);
+ numEntries++;
+ }
+
+ //We've added an entry. See if this brings us too close to full.
+ if ((numEntries+numDeadEntries) * LOAD_DENOM
+ > tableSize * LOAD_NUMER)
+ {
+ if (!resizeHash(tableSize * 2)) {
+ /* don't really have a way to indicate failure */
+ LOGE("TF hash resize failure\n");
+ }
+ }
+
+ //make sure table is not bad
+ if (numEntries < tableSize)
+ result = item;
+ }
+ } else {
+ result = pEntry->data;
+ }
+ TfHashTableUnlock();
+
+ return result;
+}
+
+/*
+ * Remove an entry from the table.
+ *
+ */
+bool TfHashTable::TfHashTableRemove(void* item)
+{
+ HashEntry* pEntry;
+ HashEntry* pEnd;
+
+ if (tableSize <= 0)
+ return false;
+
+ unsigned int itemHash = 0;
+
+ if (computeFunc) {
+ itemHash = (*computeFunc)(item);
+ }
+
+ TfHashTableLock();
+ /* jump to the first entry and probe for a match */
+ pEntry = &pEntries[itemHash & (tableSize-1)];
+ pEnd = &pEntries[tableSize];
+ while (pEntry->data != NULL) {
+ if (pEntry->data == item) {
+ if (freeFunc != NULL)
+ (*freeFunc)(pEntry->data);
+ pEntry->data = HASH_TOMBSTONE;
+ numEntries--;
+ numDeadEntries++;
+ return true;
+ }
+
+ pEntry++;
+ if (pEntry == pEnd) { /* wrap around to start */
+ if (tableSize == 1)
+ break; /* edge case - single-entry table */
+ pEntry = pEntries;
+ }
+ }
+ TfHashTableUnlock();
+
+ return false;
+}
+
+/*
+ * Round up to the next highest power of 2.
+ *
+ */
+unsigned int TfHashTable::roundUpPower2(unsigned int val)
+{
+ val--;
+ val |= val >> 1;
+ val |= val >> 2;
+ val |= val >> 4;
+ val |= val >> 8;
+ val |= val >> 16;
+ val++;
+
+ return val;
+}
+
+unsigned int TfHashTable::ComputeUtf8Hash(const char* utf8Str)
+{
+ unsigned int hash = 1;
+
+ while (*utf8Str != '\0')
+ hash = hash * 31 + *utf8Str++;
+
+ return hash;
+}
+
+/*
+ * Count up the number of tombstone entries in the hash table.
+ */
+int TfHashTable::countTombStones()
+{
+ int i, count;
+
+ for (count = i = 0; i < tableSize; i++) {
+ if (pEntries[i].data == HASH_TOMBSTONE)
+ count++;
+ }
+ return count;
+}
diff --git a/src/TestFrameworkHash.h b/src/TestFrameworkHash.h
new file mode 100644
index 0000000..1544bd3
--- /dev/null
+++ b/src/TestFrameworkHash.h
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ * Copyright (c) 2012 Code Aurora Forum. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/*
+ * General purpose hash table, used for finding classes, methods, etc.
+ *
+ * When the number of elements reaches a certain percentage of the table's
+ * capacity, the table will be resized.
+ */
+#ifndef _TESTFRAMEWORK_HASH
+#define _TESTFRAMEWORK_HASH
+
+#include <pthread.h>
+
+#define HASH_TOMBSTONE ((void*) 0xcbcacccd) // invalid ptr value
+
+/* compute the hash of an item with a specific type */
+typedef unsigned int (*HashCompute)(const void* item);
+
+/*
+ * Compare a hash entry with a "loose" item after their hash values match.
+ * Returns { <0, 0, >0 } depending on ordering of items (same semantics
+ * as strcmp()).
+ */
+typedef int (*HashCompareFunc)(const void* tableItem, const void* looseItem);
+
+/*
+ * This function will be used to free entries in the table. This can be
+ * NULL if no free is required, free(), or a custom function.
+ */
+typedef void (*HashFreeFunc)(void* ptr);
+
+/*
+ * Expandable hash table.
+ *
+ * This structure should be considered opaque.
+ */
+class TfHashTable {
+public:
+ /*
+ * Create and initialize a HashTable structure, using "initialSize" as
+ * a basis for the initial capacity of the table. (The actual initial
+ * table size may be adjusted upward.) If you know exactly how many
+ * elements the table will hold, pass the result from TfHashSize() in.)
+ *
+ * Returns "false" if unable to allocate the table.
+ */
+ TfHashTable(size_t initialSize, HashFreeFunc freeFunc,
+ HashCompareFunc cmpFunc, HashCompute computeFunc);
+
+ /*
+ * Free a hash table. Performs a "clear" first.
+ */
+ ~TfHashTable();
+
+ /*
+ * Compute the capacity needed for a table to hold "size" elements. Use
+ * this when you know ahead of time how many elements the table will hold.
+ * Pass this value into TfHashTableCreate() to ensure that you can add
+ * all elements without needing to reallocate the table.
+ */
+ size_t TfHashSize(size_t size);
+
+ /*
+ * Clear out a hash table, freeing the contents of any used entries.
+ */
+ void TfHashTableClear();
+
+ /*
+ * Look up an entry in the table, possibly adding it if it's not there.
+ *
+ * If "item" is not found, and "doAdd" is false, NULL is returned.
+ * Otherwise, a pointer to the found or added item is returned. (You can
+ * tell the difference by seeing if return value == item.)
+ *
+ * An "add" operation may cause the entire table to be reallocated. Don't
+ * forget to lock the table before calling this.
+ */
+ void* TfHashTableLookup(void* item, int len = -1, bool doAdd = false);
+
+ /*
+ * Remove an item from the hash table, given its "data" pointer. Does not
+ * invoke the "free" function; just detaches it from the table.
+ */
+ bool TfHashTableRemove(void* item);
+
+ static unsigned int ComputeUtf8Hash(const char* str);
+
+private:
+ /*
+ * Exclusive access. Important when adding items to a table, or when
+ * doing any operations on a table that could be added to by another thread.
+ */
+ void TfHashTableLock() {
+ pthread_mutex_lock(&lock);
+ }
+ void TfHashTableUnlock() {
+ pthread_mutex_unlock(&lock);
+ }
+ bool resizeHash(int newSize);
+ unsigned int roundUpPower2(unsigned int val);
+ int countTombStones();
+private:
+ /*
+ * One entry in the hash table. "data" values are expected to be (or have
+ * the same characteristics as) valid pointers. In particular, a NULL
+ * value for "data" indicates an empty slot, and HASH_TOMBSTONE indicates
+ * a no-longer-used slot that must be stepped over during probing.
+ *
+ * Attempting to add a NULL or tombstone value is an error.
+ *
+ * When an entry is released, we will call (HashFreeFunc)(entry->data).
+ */
+ struct HashEntry {
+ unsigned int hashValue;
+ void* data;
+ };
+
+private:
+ int tableSize; /* must be power of 2 */
+ int numEntries; /* current #of "live" entries */
+ int numDeadEntries; /* current #of tombstone entries */
+ HashEntry* pEntries; /* array on heap */
+ HashFreeFunc freeFunc;
+ HashCompareFunc cmpFunc;
+ HashCompute computeFunc;
+ pthread_mutex_t lock;
+};
+
+
+#endif /*_TESTFRAMEWORK_HASH*/
diff --git a/src/TestFrameworkService.cpp b/src/TestFrameworkService.cpp
new file mode 100644
index 0000000..01ed95c
--- /dev/null
+++ b/src/TestFrameworkService.cpp
@@ -0,0 +1,216 @@
+/*
+ * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of Code Aurora Forum, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define LOG_TAG "TestFrameworkService"
+
+#include <stdint.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mount.h>
+#include <sys/uio.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <utils/Errors.h>
+#include <utils/threads.h>
+#include <utils/CallStack.h>
+#include <utils/Log.h>
+#include <cutils/properties.h>
+#include <cutils/atomic.h>
+#include <binder/IServiceManager.h>
+#include <utils/String16.h>
+#include <binder/Parcel.h>
+#include <binder/IPCThreadState.h>
+#include <binder/ProcessState.h>
+#include <inc/testframework.h>
+#include "TestFramework.h"
+#include "TestFrameworkService.h"
+
+ITestFrameworkService::ITestFrameworkService() { }
+ITestFrameworkService::~ITestFrameworkService() { }
+
+const android::String16 ITestFrameworkService::descriptor(TESTFRAMEWORK_NAME);
+
+const android::String16& ITestFrameworkService::getInterfaceDescriptor() const {
+ return ITestFrameworkService::descriptor;
+}
+
+ITestFrameworkService *TestFrameworkService::RunTestFrameworkService() {
+ TestFrameworkService *service = new TestFrameworkService();
+ defaultServiceManager()->addService(ITestFrameworkService::descriptor, service);
+ ProcessState::self()->startThreadPool();
+ return (ITestFrameworkService *)service;
+}
+
+TestFrameworkService::TestFrameworkService() {
+ LOGD("TestFrameworkService created");
+ mNextConnId = 1;
+ pthread_mutex_init(&mMutex, 0);
+ TfInit();
+}
+
+TestFrameworkService::~TestFrameworkService() {
+ pthread_mutex_destroy(&mMutex);
+ LOGD("TestFrameworkService destroyed");
+}
+
+status_t TestFrameworkService::onTransact(uint32_t code,
+ const android::Parcel &data,
+ android::Parcel *reply,
+ uint32_t flags) {
+ status_t ret = android::NO_ERROR;
+ int evType = 0;
+ int status = 0;
+
+ switch(code) {
+ case TF_WRITE_FMT_MSG: {
+ CHECK_INTERFACE(ITestFrameworkService, data, reply);
+ evType = data.readInt32();
+ const char *str = data.readCString();
+ TfWrite(evType, str);
+ }
+ break;
+
+ case TF_WRITE_BUF: {
+ CHECK_INTERFACE(ITestFrameworkService, data, reply);
+ const char *str;
+ str = data.readCString();
+ TfWrite(str);
+ }
+ break;
+
+ case TF_INFO: {
+ CHECK_INTERFACE(ITestFrameworkService, data, reply);
+ data.readInt32();
+ reply->writeInt32(mLogType);
+ reply->writeInt32(mEventType);
+ reply->writeInt32(mOpenInterval);
+ reply->writeInt32(mClosedInterval);
+ }
+ break;
+
+ case TF_TURNON: {
+ CHECK_INTERFACE(ITestFrameworkService, data, reply);
+ evType = data.readInt32();
+ if (evType == TF_LOGCAT) {
+ property_set("debug.tf.enable", "logcat");
+ }
+ else if (evType == TF_TESTFRAMEWORK) {
+ property_set("debug.tf.enable", "1");
+ }
+
+ if (!TfIsValid()) {
+ TfTracersInit();
+ }
+
+ TfUpdate(evType);
+ }
+ break;
+
+ case TF_TURNOFF: {
+ CHECK_INTERFACE(ITestFrameworkService, data, reply);
+ data.readInt32();
+ property_set("debug.tf.enable", "0");
+ TfUpdate(TF_DISABLE);
+ }
+ break;
+
+ default: {
+ ret = BBinder::onTransact(code, data, reply, flags);
+ }
+ break;
+ }
+
+ return ret;
+}
+
+int TestFrameworkService::TFSInit() {
+ int ret = 0;
+
+ ret = system("su -c mount -t debugfs nodev /sys/kernel/debug");
+ if(ret >= 0) {
+ ret = system("su -c chmod 0666 "NODE_STR(tracing_on));
+ ret = system("su -c chmod 0222 "NODE_STR(trace_marker));
+ ret = system("su -c chmod 0666 "NODE_STR(buffer_size_kb));
+ ret = system("su -c chmod 0666 "NODE_STR(set_event));
+ ret = system("echo 0 > "NODE_STR(tracing_on));
+ ret = system("echo 10240 > "NODE_STR(buffer_size_kb));
+ if(ret >= 0) {
+ printf("TestFrameworkService Running...\n");
+ }
+ }
+ else {
+ LOGE("TFS: mount debugfs failed, errno=%d", errno);
+ }
+
+ if(ret < 0) {
+ printf("Failed to setup the environment, either CONFIG_FTRACE, "
+ "CONFIG_ENABLE_DEFAULT_TRACERS are not enabled or debugfs"
+ "could not be mounted, if issue is later, you may try inserting"
+ "these rules in init.rc"
+ "#debugfs"
+ "mount debugfs nodev /sys/kernel/debug"
+ "chmod 0666 /sys/kernel/debug/tracing/tracing_on"
+ "chmod 0222 /sys/kernel/debug/tracing/trace_marker"
+ "write /sys/kernel/debug/tracing/tracing_on 0");
+ }
+ //testframework init, open tracer, marker, etc.
+ LOGD("tfhash: TFSInit");
+ ret = TfInit();
+
+ property_set("debug.tf.servicerunning", "1");
+
+ return ret;
+}
+
+bool TestFrameworkService::TFSUpdate(int updatetype) {
+ char property[PROPERTY_VALUE_MAX];
+ int ex = 0;
+
+ pthread_mutex_lock(&mMutex);
+
+ if (!TfIsValid()) {
+ TfTracersInit();
+ }
+
+ TfUpdate(-1, updatetype);
+
+ pthread_mutex_unlock(&mMutex);
+
+ if (property_get("debug.tf.exit", property, "0") > 0) {
+ ex = atoi(property);
+ }
+
+ if(ex) {
+ return false;
+ }
+ return true;
+}
+
diff --git a/src/TestFrameworkService.h b/src/TestFrameworkService.h
new file mode 100644
index 0000000..3bb8a82
--- /dev/null
+++ b/src/TestFrameworkService.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of Code Aurora Forum, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _TESTFRAMEWORKSERVICE_H_
+#define _TESTFRAMEWORKSERVICE_H_
+
+#include <utils/KeyedVector.h>
+#include <utils/RefBase.h>
+#include <utils/String16.h>
+#include <utils/threads.h>
+#include <string.h>
+#include <binder/IInterface.h>
+#include <binder/Parcel.h>
+#include <utils/Log.h>
+#include "TestFrameworkCommon.h"
+
+using namespace android;
+
+#define TRACING_BASE "/sys/kernel/debug/tracing/"
+#define NODE_STR(x) TRACING_BASE#x
+
+class ITestFrameworkService: public IInterface
+{
+public:
+ DECLARE_META_INTERFACE(TestFrameworkService)
+
+ virtual int TFSInit() = 0;
+ virtual bool TFSUpdate(int updatetype = SYNC) = 0;
+};
+
+class BnTestFrameworkService : public BnInterface<ITestFrameworkService>
+{
+};
+
+class TestFrameworkService : public BnTestFrameworkService,
+ public TestFrameworkCommon
+{
+public:
+ static ITestFrameworkService *RunTestFrameworkService();
+ TestFrameworkService();
+ virtual ~TestFrameworkService();
+
+ status_t onTransact(uint32_t code,
+ const Parcel &data,
+ Parcel *reply,
+ uint32_t flags);
+
+ virtual int TFSInit();
+ virtual bool TFSUpdate(int updatetyep = SYNC);
+
+private:
+ int32_t mNextConnId;
+ pthread_mutex_t mMutex;
+};
+
+#endif
diff --git a/src/TestFrameworkServiceMain.cpp b/src/TestFrameworkServiceMain.cpp
new file mode 100644
index 0000000..54c8fcb
--- /dev/null
+++ b/src/TestFrameworkServiceMain.cpp
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of Code Aurora Forum, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define LOG_TAG "TestFrameworkServiceMain"
+
+#include <cutils/properties.h>
+#include "TestFrameworkService.h"
+#include "TFSShell.h"
+
+static pthread_mutex_t mMutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t mCond = PTHREAD_COND_INITIALIZER;
+static pthread_t mThreadID;
+
+void *TFSSync(void *s) {
+ ITestFrameworkService *service;
+
+ service = (ITestFrameworkService *)s;
+
+ if(!service) {
+ TFSShell::TFSTtyPrint("Can not run service...");
+ return NULL;
+ }
+
+ service->TFSInit();
+
+ pthread_mutex_lock(&mMutex);
+ pthread_cond_signal(&mCond);
+ pthread_mutex_unlock(&mMutex);
+
+ while(true) {
+ if (!service->TFSUpdate())
+ break;
+ /*sleep 500ms*/
+ usleep(500000);
+ }
+
+ return NULL;
+}
+
+ITestFrameworkService *SpinService() {
+ pthread_attr_t attr;
+ ITestFrameworkService *service = NULL;
+ service = TestFrameworkService::RunTestFrameworkService();
+ pthread_mutex_init(&mMutex, 0);
+ pthread_cond_init(&mCond, NULL);
+ pthread_attr_init(&attr);
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
+ pthread_create(&mThreadID, &attr, TFSSync, service);
+ pthread_attr_destroy(&attr);
+
+ pthread_mutex_lock(&mMutex);
+ pthread_cond_wait(&mCond, &mMutex);
+ pthread_mutex_unlock(&mMutex);
+
+ return service;
+}
+
+int main(int argc, char **argv)
+{
+ TFSShell sh;
+ ITestFrameworkService *service = NULL;
+
+ service = SpinService();
+ sh.MainLoop(service);
+
+ pthread_mutex_destroy(&mMutex);
+ pthread_cond_destroy(&mCond);
+
+ void *dummy;
+ pthread_join(mThreadID, &dummy);
+ status_t err = (status_t) dummy;
+
+ return 0;
+}
+