文章鏈接:http://blog.csdn.net/jiazhijun/article/details/10157901
作者:Jack_Jia 郵箱: [email protected]
一般開發者都有這樣的業務需求:統計自己應用的卸載量或在用戶卸載應用後提供反饋信息以便更好的改進軟件。
應用開發者可以通過註冊“android.intent.action.PACKAGE_REMOVED”廣播獲取卸載其它應用的信息,但該廣播不能用於應用本身被卸載。如何獲取自己被卸載的信息呢?
目前有兩種方式可以做到應用卸載提示:
第一種通過監控Android日誌實現:
啓動一個服務監控android系統的打印日誌,當監控到"android.intent.action.DELETE"並且包含自己應用的包名時,提示給用戶。代碼摘至 (http://blog.csdn.net/xyz_lmn/article/details/8330710)
缺點:耗電問題,且程序必須在啓動的情況下才可以監控。
public class AndroidLogcatScannerThread extends Thread {
private LogcatObserver observer;
public AndroidLogcatScannerThread(LogcatObserver observer) {
this.observer = observer;
}
public void run() {
String[] cmds = { "logcat", "-c" };
String shellCmd = "logcat";
Process process = null;
InputStream is = null;
DataInputStream dis = null;
String line = "";
Runtime runtime = Runtime.getRuntime();
try {
observer.handleLog(line);
int waitValue;
waitValue = runtime.exec(cmds).waitFor();
observer.handleLog("waitValue=" + waitValue + "\n Has do Clear logcat cache.");
process = runtime.exec(shellCmd);
is = process.getInputStream();
dis = new DataInputStream(is);
while ((line = dis.readLine()) != null) {
//Log.d("Log","Log.Bestpay:"+line);
if(observer!=null)
observer.handleLog(line);
}
} catch (InterruptedException e) {
e.printStackTrace();
} catch (IOException ie) {
ie.printStackTrace();
} finally {
try {
if (dis != null) {
dis.close();
}
if (is != null) {
is.close();
}
if (process != null) {
process.destroy();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
監控服務:
public class AndroidLogcatScannerService extends Service implements LogcatObserver{
@Override
public void onCreate() {
// TODO Auto-generated method stub
super.onCreate();
}
@Override
public void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
}
@Override
public void onStart(Intent intent, int startId) {
// TODO Auto-generated method stub
super.onStart(intent, startId);
AndroidLogcatScannerThread scannerThread=new AndroidLogcatScannerThread(AndroidLogcatScannerService.this);
scannerThread.start();
}
@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
@Override
public void handleLog(String info) {
// TODO Auto-generated method stub
if (info.contains("android.intent.action.DELETE") && info.contains(getPackageName())) {
Intent intent = new Intent();
intent.setClass(AndroidLogcatScannerService.this, UninstallActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
}
}
第二種通過Fork子進程,然後在子進程中通過監控/data/data/{package_name}目錄變化實現應用卸載提示,當私有目錄被刪除時,本應用即被卸載。”豌豆莢“即時使用該中方式。下面我們通過逆向分析“豌豆莢”來看看該功能具體實現。
豌豆莢被卸載後,總是調用瀏覽器打開如下頁面:
在逆向過程中發現,即使在設置->應用程序中強制停止豌豆莢相關應用,當卸載豌豆莢是仍然可以調起瀏覽器訪問反饋頁面。豌豆莢是如何做到的呢?
豌豆莢啓動後,主要涉及以下三個進程:
當在設置->應用程序中強制關閉豌豆莢相關應用後,我們觀察進程變化:
發現在設置->應用程序中強制關閉並不能關閉uuid_sys進程,那麼卸載反饋邏輯肯定就在uuid_sys進程中完成了!
在豌豆莢APK安裝包存在lib\armeabi\libuuid.so文件,該文件並不是共享庫文件而是一個可執行文件。
使用IDA逆向libuuid.so文件,實現關鍵代碼如下:
1、使用linux inotify_init、inotify_add_watch監控文件系統目錄/data/data/com.wandoujia.phoenix2的變化。
2、當監控目錄被刪除時說明程序被卸載,通過am命令啓動瀏覽器打開指定網頁。