/* 头文件begin */
#include "UninstalledObserver.h"
/* 头文件end */
#ifdef __cplusplus
extern
"C"
{
#endif
/* 内全局变量begin */
static
char TAG
[]
=
"UninstalledObserver"
;
static jboolean isCopy
= JNI_TRUE
;
static
const
char ObserverProcessName
[]
=
"com.baidu.video:observer"
;
static
const
char APP_DIR
[]
=
"/data/data/com.baidu.video/lib"
;
static
const
char APP_FILES_DIR
[]
=
"/data/data/com.baidu.video/files"
;
static
char
* APP_OBSERVED_FILE
=
"/data/data/com.baidu.video/files/observedFile"
;
//static char* APP_OBSERVED_FILE = "/data/data/com.baidu.video/databases/bdplayer_database";
static
char
* APP_FEEDBACK_URL
=
"http://www.baidu.com"
;
static
const
char APP_LOCK_FILE
[]
=
"/data/data/com.baidu.video/files/lockFile"
;
int watchDescriptor
;
int fileDescriptor
;
pid_t observer
=-
1
;
/* 内全局变量 */
/*
* Class: com_baidu_video_UninstalledObserver
* Method: init
* Signature: ()V
* return: 子进程pid
*/
JNIEXPORT
int JNICALL
Java_com_baidu_video_UninstalledObserver_init
(JNIEnv
*env
, jobject obj
, jstring userSerial
,
jstring path
,jstring url
,jstring uploadData
)
{
int isObserverAlive
=
-
1
;
isObserverAlive
=
isObserverProcessAlive
(APP_OBSERVED_FILE
);
if
(isObserverAlive
==
0
){
//判断到监听进程还在
return observer
;
}
if
(path
!= NULL
){
APP_OBSERVED_FILE
=(*env
)->
GetStringUTFChars
(env
,path
,
0
);
}
// fork子进程,以执行轮询任务
pid_t pid
=
fork
();
if
(pid
<
0
)
{
//fork failed !!!
exit
(
1
);
}
else
if
(pid
==
0
)
{
//保存监听进程id
writePidFile
(APP_OBSERVED_FILE
);
// 分配空间,以便读取event
void
*p_buf
=
malloc
(
sizeof
(
struct inotify_event
));
if
(p_buf
== NULL
)
{
//malloc failed !!!
exit
(
1
);
}
// 分配空间,以便打印mask
int maskStrLength
=
7
+
10
+
1
;
// mask=0x占7字节,32位整形数最大为10位,转换为字符串占10字节,'\0'占1字节
char
*p_maskStr
=
malloc
(maskStrLength
);
if
(p_maskStr
== NULL
)
{
free
(p_buf
);
exit
(
1
);
}
// 开始监听
startObserver
(env
,p_buf
,p_maskStr
);
while
(
1
)
{
// 开始循环监听
size_t readBytes
=
read
(fileDescriptor
, p_buf
,
sizeof
(
struct inotify_event
));
// 若文件被删除,可能是已卸载,还需进一步判断app文件夹是否存在
if
(IN_DELETE_SELF
==
((
struct inotify_event
*) p_buf
)->mask
)
{
FILE
*p_appDir
=
fopen
(APP_DIR
,
"r"
);
if
(p_appDir
!= NULL
){
//应用主目录还在(可能还没有来得及清除),sleep(2)等等再看看
sleep
(
2
);
p_appDir
=
fopen
(APP_DIR
,
"r"
);
}
// 确认已卸载
if
(p_appDir
== NULL
)
{
inotify_rm_watch
(fileDescriptor
, watchDescriptor
);
break
;
}
// 未卸载,可能用户执行了"清除数据"
else
{
fclose
(p_appDir
);
//应用没有卸载,重新监听
startObserver
(env
,p_buf
,p_maskStr
);
}
}
}
remove
(APP_OBSERVED_FILE
);
remove
(APP_LOCK_FILE
);
// 释放资源
free
(p_buf
);
free
(p_maskStr
);
// 停止监听
char
*szWebAddr
=
(*env
)->
GetStringUTFChars
(env
,url
,
0
);
char
*szRequest
=(*env
)->
GetStringUTFChars
(env
,uploadData
,
0
);
if
(szWebAddr
&& szRequest
){
//APP_FEEDBACK_URL= (*env)->GetStringUTFChars(env,url, 0);
uploadStatData
(szWebAddr
, szRequest
);
}
else
{
//LOG_DEBUG("UninstalledObserver","url == NULL,不能进行打点。。。。");
}
free
(szWebAddr
);
free
(szRequest
);
if
(userSerial
== NULL
)
{
// 执行命令am start -a android.intent.action.VIEW -d $(url)
execlp
(
"am"
,
"am"
,
"start"
,
"-a"
,
"android.intent.action.VIEW"
,
"-d"
, APP_FEEDBACK_URL
,
(
char
*)NULL
);
}
else
{
// 执行命令am start --user userSerial -a android.intent.action.VIEW -d $(url)
execlp
(
"am"
,
"am"
,
"start"
,
"--user"
, (*env)->GetStringUTFChars(env, userSerial, &isCopy), "-a", "android.intent.action.VIEW", "-d", APP_FEEDBACK_URL, (char *)NULL);
}
exit
(
0
);
}
else
{
// 父进程直接退出,使子进程被init进程领养,以避免子进程僵死,同时返回子进程pid
return pid
;
}
}
void
startObserver
(JNIEnv
*env
,
void
*p_buf
,
char
*p_maskStr
){
jstring tag
=
(*env
)->
NewStringUTF
(env
, TAG
);
// 若监听文件所在文件夹不存在,退出监听
FILE
*p_filesDir
=
fopen
(APP_FILES_DIR
,
"r"
);
if
(p_filesDir
== NULL
)
{
exit
(
1
);
}
// 若被监听文件不存在,退出监听
FILE
*p_observedFile
=
fopen
(APP_OBSERVED_FILE
,
"r"
);
if
(p_observedFile
== NULL
)
{
exit
(
1
);
}
fclose
(p_observedFile
);
// 通过检测加锁状态来保证只有一个卸载监听进程
int lockFileDescriptor
=
open
(APP_LOCK_FILE
, O_RDONLY
);
if
(lockFileDescriptor
==
-
1
)
{
exit
(
1
);
}
int lockRet
=
flock
(lockFileDescriptor
, LOCK_EX | LOCK_NB
);
if
(lockRet
==
-
1
)
{
exit
(
0
);
}
// 初始化
fileDescriptor
=
inotify_init
();
if
(fileDescriptor
<
0
)
{
free
(p_buf
);
free
(p_maskStr
);
exit
(
1
);
}
watchDescriptor
=
inotify_add_watch
(fileDescriptor
, APP_OBSERVED_FILE
, IN_ALL_EVENTS
);
if
(watchDescriptor
<
0
)
{
free
(p_buf
);
free
(p_maskStr
);
exit
(
1
);
}
}
/*** 检测到卸载应用时候向服务器上传打点数据
szWebAddr: 页面地址(包含host+addr)
szRequest: 请求内容
**/
int
uploadStatData
(
char
*szWebAddr
,
char
*szRequest
)
{
int sockfd
, ret
, responseDataLength
, selectResult
;
struct sockaddr_in servaddr
;
char sockData
[BUFSIZEBIG
], buf
[BUFSIZEBIG
],
*szRequestLength
;
socklen_t len
;
fd_set t_set1
;
struct timeval tv
;
struct hostent
*pHostent
= NULL
;
// int i,j;
// char webAddr[128];
// char szRequestData[BUFSIZEBIG];
//LOG_DEBUG("UninstalledObserver","开始打点");
if
((sockfd
=
socket
(AF_INET
, SOCK_STREAM
,
0
))
<
0
)
{
//LOG_DEBUG("UninstalledObserver","创建网络连接失败,本线程即将终止---socket error!\n");
exit
(
0
);
};
if
(!szWebAddr
){
//LOG_DEBUG("UninstalledObserver","if(!szWebAddr) return 0;");
return
0
;
}
// for(i=0;i
// webAddr[i]=szWebAddr[i];
// }
// //LOG_DEBUG("UninstalledObserver","上传地址:");
// //LOG_DEBUG("UninstalledObserver",webAddr);
bzero
(&servaddr
,
sizeof
(servaddr
));
servaddr
.sin_family
= AF_INET
;
servaddr
.sin_port
=
htons
(PORT
);
//获取hostent
pHostent
=
gethostbyname
(szWebAddr
);
if
(!pHostent
)
{
//LOG_DEBUG("UninstalledObserver","if(!pHostent) return 0;");
// if (inet_pton(AF_INET, IPSTR, &servaddr.sin_addr) <= 0 ){
// //LOG_DEBUG("UninstalledObserver","创建网络连接失败,本线程即将终止 exit(0);");
// exit(0);
// };
return
0
;
}
else
{
servaddr
.sin_addr
.s_addr
=
((
struct in_addr
*)(pHostent
->h_addr
))->s_addr
;
}
if
(
connect
(sockfd
,
(
struct sockaddr
*)&servaddr
,
sizeof
(servaddr
))
<
0
){
//LOG_DEBUG("UninstalledObserver","连接到服务器失败,connect error!");
exit
(
0
);
}
//LOG_DEBUG("UninstalledObserver","与远端建立了连接!");
//发送数据
szRequestLength
=(
char
*)
malloc
(
128
);
len
=
strlen
(szRequest
);
sprintf
(szRequestLength
,
"%d"
, len
);
memset
(sockData
,
0
, BUFSIZEBIG
);
strcat
(sockData
,
"POST /postlog/?app=androidphone HTTP/1.1\n"
);
strcat
(sockData
,
"Host: app.video.baidu.com\n"
);
//strcat(sockData, "Host: cq01-video-rdtest01.vm.baidu.com\n");
strcat
(sockData
,
"Content-Type: application/x-www-form-urlencoded\n"
);
strcat
(sockData
,
"Content-Length: "
);
strcat
(sockData
, szRequestLength
);
strcat
(sockData
,
"\n\n"
);
strcat
(sockData
, szRequest
);
strcat
(sockData
,
"\r\n\r\n"
);
// for(j=0;j
// szRequestData[j]=szRequest[j];
// }
// //LOG_DEBUG("UninstalledObserver","上传数据:");
// //LOG_DEBUG("UninstalledObserver",szRequestData);
ret
=
write
(sockfd
,sockData
,
strlen
(sockData
));
if
(ret
<
0
)
{
//LOG_DEBUG("UninstalledObserver","打点失败!");
exit
(
0
);
}
else
{
//LOG_DEBUG("UninstalledObserver","打点成功!");
}
FD_ZERO
(&t_set1
);
FD_SET
(sockfd
,
&t_set1
);
while
(
1
){
sleep
(
1
);
tv
.tv_sec
=
0
;
tv
.tv_usec
=
0
;
selectResult
=
0
;
selectResult
=
select
(sockfd
+
1
,
&t_set1
, NULL
, NULL
,
&tv
);
if
(selectResult
<
0
)
{
close
(sockfd
);
//LOG_DEBUG("UninstalledObserver","在读取数据报文时SELECT检测到异常,该异常导致线程终止!return -1;");
return
-
1
;
};
if
(selectResult
>
0
){
memset
(buf
,
0
, BUFSIZEBIG
);
responseDataLength
=
read
(sockfd
, buf
, BUFSIZEBIG
-
1
);
if
(responseDataLength
==
0
){
close
(sockfd
);
//LOG_DEBUG("UninstalledObserver","读取数据报文时发现远端关闭,该线程终止!");
return
-
1
;
}
//LOG_DEBUG("UninstalledObserver","服务器响应数据: ");
//LOG_DEBUG("UninstalledObserver",buf);
}
}
close
(sockfd
);
return
0
;
}
/**
* @Brief write the pid into the szPidFile
*
* @Param szPidFile name of pid file
*/
void
writePidFile
(
const
char
*szPidFile
)
{
/*open the file*/
char str
[
32
];
int pidFile
=
open
(szPidFile
, O_WRONLY|O_TRUNC
);
if
(pidFile
<
0
)
{
exit
(
1
);
}
/*F_LOCK(block&lock) F_TLOCK(try&lock) F_ULOCK(unlock) F_TEST(will not lock)*/
if
(
flock
(pidFile
, LOCK_EX | LOCK_NB
)
<
0
)
{
//if (lockf(pidFile, F_TLOCK, 0) < 0) {
fprintf
(stderr
,
"Can't lockf Pid File: %s"
, szPidFile
);
//LOG_DEBUG("UninstalledObserver","writePidFile: Can't lockf Pid File");
exit
(
1
);
}
/*get the pid,and write it to the pid file.*/
sprintf
(str
,
"%d\n"
,
getpid
());
ssize_t len
=
strlen
(str
);
ssize_t ret
=
write
(pidFile
, str
, len
);
//fprintf (pFile, " %d ",getpid());
//LOG_DEBUG("UninstalledObserver","writePidFile: 监听进程pid如下");
//LOG_DEBUG("UninstalledObserver",str);
if
(ret
!= len
)
{
fprintf
(stderr
,
"Can't Write Pid File: %s"
, szPidFile
);
//LOG_DEBUG("UninstalledObserver","writePidFile: Can't Write Pid File");
exit
(
1
);
}
close
(pidFile
);
//LOG_DEBUG("UninstalledObserver","writePidFile: 成功保存了监听进程pid");
}
int
isObserverProcessAlive
(
const
char
*szPidFile
){
FILE
*pidFile
;
int i
;
char observerPID
[
32
];
if
((pidFile
=
fopen
(szPidFile
,
"rb"
))==NULL
){
//LOG_DEBUG("UninstalledObserver","isObserverProcessAlive: Can't Open Pid File");
return
1
;
}
//fread(&observerPID,sizeof(observerPID),1,pidFile);
fscanf
(pidFile
,
"%d"
,
&observer
);
fclose
(pidFile
);
if
(observer
>
1
){
sprintf
(observerPID
,
"%d\n"
, observer
);
//LOG_DEBUG("UninstalledObserver","isObserverProcessAlive: 读取到上次存入的pid");
//LOG_DEBUG("UninstalledObserver",observerPID);
if
(
kill
(observer
,
0
)
==
0
){
//LOG_DEBUG("UninstalledObserver","isObserverProcessAlive: 判断到监听进程还在。");
return
0
;
}
//LOG_DEBUG("UninstalledObserver","isObserverProcessAlive: 判断到监听进程已不存在。");
}
else
{
//LOG_DEBUG("UninstalledObserver","isObserverProcessAlive: 没有读取到上次存入的pid,无法判断监听进程是否还在。");
return
1
;
}
}
#ifdef __cplusplus
}
#endif