1. 程式人生 > >Android應用如何監聽自己是否被解除安裝及解除安裝反饋功能的實現(第三版)

Android應用如何監聽自己是否被解除安裝及解除安裝反饋功能的實現(第三版)

  1 /* 標頭檔案begin */
  2 #include "main_activity_UninstalledObserverActivity.h"
  3 /* 標頭檔案end */
  4 
  5 #ifdef __cplusplus
  6 extern "C"
  7 {
  8 #endif
  9 
 10 /* 內全域性變數begin */
 11 static char TAG[] = "UninstalledObserverActivity.init";
 12 static jboolean isCopy = JNI_TRUE;
 13 
 14 static const char APP_DIR[] = "/data/data/pym.test.uninstalledobserver";
 15 static const char APP_FILES_DIR[] = "/data/data/pym.test.uninstalledobserver/files";
 16 static const char APP_OBSERVED_FILE[] = "/data/data/pym.test.uninstalledobserver/files/observedFile";
 17 static const char APP_LOCK_FILE[] = "/data/data/pym.test.uninstalledobserver/files/lockFile";
 18 /* 內全域性變數 */
 19 
 20 /*
 21  * Class:     main_activity_UninstalledObserverActivity
 22  * Method:    init
 23  * Signature: ()V
 24  * return: 子程序pid
 25  */
 26 JNIEXPORT int JNICALL Java_main_activity_UninstalledObserverActivity_init(JNIEnv *env, jobject obj, jstring userSerial)
 27 {
 28     jstring tag = (*env)->NewStringUTF(env, TAG);
 29 
 30     LOG_DEBUG((*env)->GetStringUTFChars(env, tag, &isCopy)
 31             , (*env)->GetStringUTFChars(env, (*env)->NewStringUTF(env, "init observer"), &isCopy));
 32 
 33     // fork子程序,以執行輪詢任務
 34     pid_t pid = fork();
 35     if (pid < 0)
 36     {
 37         LOG_ERROR((*env)->GetStringUTFChars(env, tag, &isCopy)
 38                 , (*env)->GetStringUTFChars(env, (*env)->NewStringUTF(env, "fork failed !!!"), &isCopy));
 39 
 40         exit(1);
 41     }
 42     else if (pid == 0)
 43     {
 44         // 若監聽檔案所在資料夾不存在,建立
 45         FILE *p_filesDir = fopen(APP_FILES_DIR, "r");
 46         if (p_filesDir == NULL)
 47         {
 48             int filesDirRet = mkdir(APP_FILES_DIR, S_IRWXU | S_IRWXG | S_IXOTH);
 49             if (filesDirRet == -1)
 50             {
 51                 LOG_ERROR((*env)->GetStringUTFChars(env, tag, &isCopy)
 52                         , (*env)->GetStringUTFChars(env, (*env)->NewStringUTF(env, "mkdir failed !!!"), &isCopy));
 53 
 54                 exit(1);
 55             }
 56         }
 57 
 58         // 若被監聽檔案不存在,建立檔案
 59         FILE *p_observedFile = fopen(APP_OBSERVED_FILE, "r");
 60         if (p_observedFile == NULL)
 61         {
 62             p_observedFile = fopen(APP_OBSERVED_FILE, "w");
 63         }
 64         fclose(p_observedFile);
 65 
 66         // 建立鎖檔案,通過檢測加鎖狀態來保證只有一個解除安裝監聽程序
 67         int lockFileDescriptor = open(APP_LOCK_FILE, O_RDONLY);
 68         if (lockFileDescriptor == -1)
 69         {
 70             lockFileDescriptor = open(APP_LOCK_FILE, O_CREAT);
 71         }
 72         int lockRet = flock(lockFileDescriptor, LOCK_EX | LOCK_NB);
 73         if (lockRet == -1)
 74         {
 75             LOG_DEBUG((*env)->GetStringUTFChars(env, tag, &isCopy)
 76                     , (*env)->GetStringUTFChars(env, (*env)->NewStringUTF(env, "observed by another process"), &isCopy));
 77 
 78             exit(0);
 79         }
 80         LOG_DEBUG((*env)->GetStringUTFChars(env, tag, &isCopy)
 81                     , (*env)->GetStringUTFChars(env, (*env)->NewStringUTF(env, "observed by child process"), &isCopy));
 82 
 83         // 分配空間,以便讀取event
 84         void *p_buf = malloc(sizeof(struct inotify_event));
 85         if (p_buf == NULL)
 86         {
 87             LOG_ERROR((*env)->GetStringUTFChars(env, tag, &isCopy)
 88                     , (*env)->GetStringUTFChars(env, (*env)->NewStringUTF(env, "malloc failed !!!"), &isCopy));
 89 
 90             exit(1);
 91         }
 92         // 分配空間,以便列印mask
 93         int maskStrLength = 7 + 10 + 1;// mask=0x佔7位元組,32位整形數最大為10位,轉換為字串佔10位元組,'\0'佔1位元組
 94         char *p_maskStr = malloc(maskStrLength);
 95         if (p_maskStr == NULL)
 96         {
 97             free(p_buf);
 98 
 99             LOG_ERROR((*env)->GetStringUTFChars(env, tag, &isCopy)
100                     , (*env)->GetStringUTFChars(env, (*env)->NewStringUTF(env, "malloc failed !!!"), &isCopy));
101 
102             exit(1);
103         }
104 
105         // 開始監聽
106         LOG_DEBUG((*env)->GetStringUTFChars(env, tag, &isCopy)
107                 , (*env)->GetStringUTFChars(env, (*env)->NewStringUTF(env, "start observe"), &isCopy));
108 
109         // 初始化
110         int fileDescriptor = inotify_init();
111         if (fileDescriptor < 0)
112         {
113             free(p_buf);
114             free(p_maskStr);
115 
116             LOG_ERROR((*env)->GetStringUTFChars(env, tag, &isCopy)
117                     , (*env)->GetStringUTFChars(env, (*env)->NewStringUTF(env, "inotify_init failed !!!"), &isCopy));
118 
119             exit(1);
120         }
121 
122         // 新增被監聽檔案到監聽列表
123         int watchDescriptor = inotify_add_watch(fileDescriptor, APP_OBSERVED_FILE, IN_ALL_EVENTS);
124         if (watchDescriptor < 0)
125         {
126             free(p_buf);
127             free(p_maskStr);
128 
129             LOG_ERROR((*env)->GetStringUTFChars(env, tag, &isCopy)
130                     , (*env)->GetStringUTFChars(env, (*env)->NewStringUTF(env, "inotify_add_watch failed !!!"), &isCopy));
131 
132             exit(1);
133         }
134 
135         while(1)
136         {
137             // read會阻塞程序
138             size_t readBytes = read(fileDescriptor, p_buf, sizeof(struct inotify_event));
139 
140             // 列印mask
141             snprintf(p_maskStr, maskStrLength, "mask=0x%x\0", ((struct inotify_event *) p_buf)->mask);
142             LOG_DEBUG((*env)->GetStringUTFChars(env, tag, &isCopy)
143                     , (*env)->GetStringUTFChars(env, (*env)->NewStringUTF(env, p_maskStr), &isCopy));
144 
145             // 若檔案被刪除,可能是已解除安裝,還需進一步判斷app資料夾是否存在
146             if (IN_DELETE_SELF == ((struct inotify_event *) p_buf)->mask)
147             {
148                 FILE *p_appDir = fopen(APP_DIR, "r");
149                 // 確認已解除安裝
150                 if (p_appDir == NULL)
151                 {
152                     inotify_rm_watch(fileDescriptor, watchDescriptor);
153 
154                     break;
155                 }
156                 // 未解除安裝,可能使用者執行了"清除資料"
157                 else
158                 {
159                     fclose(p_appDir);
160 
161                     // 重新建立被監聽檔案,並重新監聽
162                     FILE *p_observedFile = fopen(APP_OBSERVED_FILE, "w");
163                     fclose(p_observedFile);
164 
165                     int watchDescriptor = inotify_add_watch(fileDescriptor, APP_OBSERVED_FILE, IN_ALL_EVENTS);
166                     if (watchDescriptor < 0)
167                     {
168                         free(p_buf);
169                         free(p_maskStr);
170 
171                         LOG_ERROR((*env)->GetStringUTFChars(env, tag, &isCopy)
172                                 , (*env)->GetStringUTFChars(env, (*env)->NewStringUTF(env, "inotify_add_watch failed !!!"), &isCopy));
173 
174                         exit(1);
175                     }
176                 }
177             }
178         }
179 
180         // 釋放資源
181         free(p_buf);
182         free(p_maskStr);
183 
184         // 停止監聽
185         LOG_DEBUG((*env)->GetStringUTFChars(env, tag, &isCopy)
186                 , (*env)->GetStringUTFChars(env, (*env)->NewStringUTF(env, "stop observe"), &isCopy));
187 
188         if (userSerial == NULL)
189         {
190             // 執行命令am start -a android.intent.action.VIEW -d $(url)
191             execlp("am", "am", "start", "-a", "android.intent.action.VIEW", "-d", "http://www.baidu.com", (char *)NULL);
192         }
193         else
194         {
195             // 執行命令am start --user userSerial -a android.intent.action.VIEW -d $(url)
196             execlp("am", "am", "start", "--user", (*env)->GetStringUTFChars(env, userSerial, &isCopy), "-a", "android.intent.action.VIEW", "-d", "http://www.baidu.com", (char *)NULL);
197         }
198 
199         // 執行命令失敗log
200         LOG_ERROR((*env)->GetStringUTFChars(env, tag, &isCopy)
201                 , (*env)->GetStringUTFChars(env, (*env)->NewStringUTF(env, "exec AM command failed !!!"), &isCopy));
202     }
203     else
204     {
205         // 父程序直接退出,使子程序被init程序領養,以避免子程序僵死,同時返回子程序pid
206         return pid;
207     }
208 }
209 
210 #ifdef __cplusplus
211 }
212 #endif

相關推薦

Android應用如何自己是否解除安裝解除安裝反饋功能實現

1 /* 標頭檔案begin */ 2 #include "main_activity_UninstalledObserverActivity.h" 3 /* 標頭檔案end */ 4 5 #ifdef __cplusplus 6 extern "C" 7 { 8 #en

瘋狂Android講義書本內容程式碼下載

筆者最近在通過這本書學習Android開發,書本中許多程式碼內容量比較大,便從書本中贈送的光盤裡匯出書中的程式碼,共19章以壓縮包的方式打包給大家。 附:瘋狂Android講義(第三版) 電紙書下載 關於光碟中的程式碼版本偏低,請根據自己

譚浩強C語言程式設計部分課後題答案,自己整理的

第一篇部落格,也不知道怎麼寫,就把以前的筆記發上來吧 學了半年後寫的,可能稍顯不規範,或有的多餘,將就看吧,也不想再改了 1.5 #include<stdio.h> void main() {printf("******************\n");pr

Android應用如何自己是否解除安裝解除安裝反饋功能實現第二

原文地址為: Android應用如何監聽自己是否被解除安裝及解除安裝反饋功能的實現(第二版)   昨天發了一篇有關監聽自己是否被解除安裝和解除安裝反饋功能實現的部落格,地址如下:http://www.cnblogs.com/zealotrouge/p/3157126.html,發出去後收

Android應用如何自己是否解除安裝解除安裝反饋功能實現

  一個應用被使用者解除安裝肯定是有理由的,而開發者卻未必能得知這一重要的理由,畢竟使用者很少會主動反饋建議,多半就是用得不爽就卸,如果能在被解除安裝後獲取到使用者的一些反饋,那對開發者進一步改進應用是非常有利的。目前據我所知,國內的Android應用中實現這一功能的只有360手機衛士、360平板衛士,那麼如

Android APP自己解除安裝以及解除安裝後的邏輯處理

兩個月前發了兩篇有關監聽自己是否被解除安裝和解除安裝反饋功能實現的部落格,第二版的地址如下:http://www.cnblogs.com/zealotrouge/p/3159772.html,感謝@whiletrue_童鞋發現了我的程式碼在4.2.2系統上無法實現解除安裝反饋,經過除錯,有了問題的解決方案

Android五天樂ListFragment與ViewPager

viewgroup cat () wid group 得到 ica bottom csdn 1ListFragment 今天首先學習了一種很經常使用的展示場景:列表展示。 昨天學習了使用Fragmet來取代activity進行設計。今天在托管單

java小白自己動手開發一個網站之搭建一個網站需要啥2回

新手小白,大神們看到什麼問題,請多多指出 目錄 新手小白,大神們看到什麼問題,請多多指出 搭建網站的流程 註冊域名 購買空間 製作網站 搭建網站的流程 搭建網站有哪些流程 1\註冊域名  2\購買空間  3\製作網站  &

Oracle Database 12c DBA文官手冊8——12章 實時應用群集

1概述RAC資料庫是高度可用和可擴充套件的。每個節點都必須有各自的Oralce許可和RAC許可。需權衡獲得高可用的代價。1.1硬體配置至少兩個節點,具備服務 器元件基本冗餘特性。共享儲存的內建冗餘可降低建立ASM磁碟組的軟體冗餘量。1.2軟體配置從Oracle10g自帶群集軟體服務CRS,須先在CRS_HOM

Oracle Database 12c DBA文官手冊8——5章 開發和實現應用程式

5.2、資源管理5.2.1、實現資料庫資源管理需要建立資源計劃、資源消費者組和資源計劃指令。使用資源管理器命令前須建立“未決區域”。針對會話啟用ADMINISTRATOR_RESOURCE_MAANAGER系統許可權將使用者賦給資源消費者組建立資源計劃指令分配相關資源1 切換消費者組2 使用SQL配置檔案5.

Oracle Database 12c DBA文官手冊8——5章 開發和實現應用程式

1 調整設計:最佳實踐         1.1做盡可能 少的工作             應該簡化應用

Oracle Database 12c DBA文官手冊8——5章 開發和實現應用程序

調整 pac 生成 bms 百分比 列數 改變 應用程序 數據塊 5.2、資源管理5.2.1、實現數據庫資源管理需要創建資源計劃、資源消費者組和資源計劃指令。使用資源管理器命令前須創建“未決區域”。針對會話啟用ADMINISTRATOR_RESOURCE_MAANAGER系

[分享]《Flask Web開發:基於Python的Web應用開發實戰2》中文PDF+源代碼

全面介紹 flask 技術 ESS nfs 圖片 ges web應用開發 復制粘貼 下載:Flask Web開發第二版《Flask Web開發:基於Python的Web應用開發實戰》第二版中文PDF,324頁,帶目錄和書簽,文字能夠復制粘貼;配套源代碼;經典書籍第二版,講解

Android回聲消除功能實現原始碼、編譯

好久沒寫部落格了,今天抽空把這段時間對Android平臺回升消除模組的研究進行一下總結。不要心急哦,下面我會把這個專案的原始碼都開放出來的。 一、回聲消除介紹 傳統的回聲消除都是採用硬體方式,在硬體電路上整合DSP處理晶片,如我們常用的固定電話、手機等都有專門的迴音消除處

6.2Android程式設計權威指南3————Android版本相容、最低版本、目標版本、編譯版本

Android SDK與版本相容 各種裝置遲緩的版本升級再加上Google定期的新版本釋出,給Android程式設計帶來了嚴重的相容性問題。對於增量版本,向下相容一般問題不大。主要版本向下相容才是大麻煩。也就是說,僅支援5.x版本的工作量不大,但需要支援到4.x的話,考慮到這麼多不同版本的

6.1Android程式設計權威指南3————Android SDK版本

每一個有釋出代號的版本隨後都會有相應的增量版本。例如,Ice Cream Sandwich最初的釋出版本為Android 4.0(API 14級),但沒過多久,Android 4.0.3及4.0.4(API 15級)的增量發行版本就取代了它。 為什麼仍有這麼多裝置執行著老版本And

4.3Android程式設計權威指南3————Android特有的除錯工具Android Lint

Android Lint是Android應用程式碼的靜態分析器(static analyzer)。作為一個特殊程式,它能在不執行程式碼的情況下檢查程式碼錯誤。憑著Android框架的熟練掌握,Android Lint能深入檢查程式碼,找出編譯器無法發現的問題。在大多數情況下,Android

4.2Android程式設計權威指南3————應用除錯二:設定斷點

如圖,可以在某一行程式碼左側打上斷點,斷點會在斷點設定行的前一行處停止程式碼執行,然後可以逐行檢查程式碼,為啟用程式碼偵錯程式並觸發已設定的斷點,需要除錯執行而不是直接執行應用。要除錯執行應用,單擊Run按鈕旁邊的Debug按鈕,或選擇Run → Debug ‘app’ 選單項。應用啟動並

《矩陣分析與應用2張賢達》PDF+《Python程式設計從入門到實踐》中英文PDF+原始碼

下載:https://pan.baidu.com/s/1R8hwv-PZ7DYsl_gUtLWrag 《矩陣分析與應用(第二版)張賢達》PDF 下載:https://pan.baidu.com/s/1hxfM_cL7hGpz7baorzuTjw 《Python程式設計從入門到實踐》(高清中文版PDF+高

資料庫系統原理應用教程複習筆記3

最近在複習資料庫相關知識點,過幾天就要考試了; 第一章 資料庫基礎知識 1、資料庫管理是資料處理的基礎工作,資料庫是資料管理的技術和手段。資料庫中的資料具有整體性和共享性。 1.2、資料庫系統的核心:資料庫管理系統。 1.3、資料庫核心:資料模型; 2、資料庫(DB)是一個按資料結構來儲存和管理資料的