Android 监听应用卸载:弹出反馈界面并上传客户端数据

/* 头文件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<strlen(szWebAddr);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<len;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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值