溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

android監(jiān)聽(tīng)?wèi)?yīng)用是否被卸載的方法

發(fā)布時(shí)間:2020-06-05 15:27:23 來(lái)源:億速云 閱讀:476 作者:Leah 欄目:移動(dòng)開(kāi)發(fā)

這篇文章主要介紹了android監(jiān)聽(tīng)?wèi)?yīng)用是否被卸載的方法,具有一定借鑒價(jià)值,需要的朋友可以參考下。如下資料是關(guān)于android實(shí)現(xiàn)監(jiān)聽(tīng)的詳細(xì)步驟內(nèi)容。

一  效果演示


    打開(kāi)應(yīng)用效果圖:

android監(jiān)聽(tīng)?wèi)?yīng)用是否被卸載的方法

    圖1


    點(diǎn)擊卸載后提示,如下圖:

android監(jiān)聽(tīng)?wèi)?yīng)用是否被卸載的方法

    圖2

    然后退出應(yīng)用,卸載程序,會(huì)發(fā)現(xiàn)當(dāng)應(yīng)用被卸載以后,會(huì)彈出調(diào)用瀏覽器的提示,這里隨便放了一個(gè)搜狐瀏覽頁(yè)面,在自己的應(yīng)用中應(yīng)該調(diào)用的一般都是調(diào)查頁(yè)面。如下圖:

android監(jiān)聽(tīng)?wèi)?yīng)用是否被卸載的方法

    圖3


    ok,效果前面已經(jīng)演示了,現(xiàn)在需要討論一下其具體實(shí)現(xiàn)了。

    首先,通過(guò)adb shell進(jìn)入手機(jī),然后第一次進(jìn)入應(yīng)用,像圖1一樣,不點(diǎn)擊按鈕,通過(guò) ps | busybox grep ubuntu 看這個(gè)應(yīng)用的進(jìn)程信息,如下圖:

android監(jiān)聽(tīng)?wèi)?yīng)用是否被卸載的方法

   這個(gè)時(shí)候只有

   u0_a108   2953  124   490956 47792 ffffffff 40052a40 S com.example.ubuntuforandroid
   2953 這一個(gè)進(jìn)程


   點(diǎn)擊 卸載后提示 按鈕再次,執(zhí)行剛才執(zhí)行的ps命令,發(fā)現(xiàn)已經(jīng)有兩個(gè)進(jìn)程了如下圖:

android監(jiān)聽(tīng)?wèi)?yīng)用是否被卸載的方法


  其實(shí)新產(chǎn)生的進(jìn)程是通過(guò)程序調(diào)用jni接口


public static native int Reguninstall(String path,String url);


  這個(gè)接口fork了一個(gè)進(jìn)程,而新fork的進(jìn)程負(fù)責(zé)監(jiān)聽(tīng)本應(yīng)用是否被卸載了


二  源碼分析


  java層的代碼如下,很簡(jiǎn)單,就是調(diào)用一下jni接口


protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
                                                                                                                                                                                                                                                                                                      
    setContentView(R.layout.activity_main);
                                                                                                                                                                                                                                                                                              
    initInjectFunction("testfile");
                                                                                                                                                                                                                                                                                              
    test = (TextView)this.findViewById(R.id.testview);
    test.setText("點(diǎn)擊卸載后提示按鈕,你的應(yīng)用在卸載以后會(huì)調(diào)用瀏覽器,然后調(diào)用你需要的頁(yè)面。");
                                                                                                                                                                                                                                                                                              
                                                                                                                                                                                                                                                                                                     
    btn = (Button)this.findViewById(R.id.testbtn);
    btn.setOnClickListener(new View.OnClickListener() {
                                                                                                                                                                                                                                                                                                  
        @Override
        public void onClick(View v) {
            // TODO Auto-generated method stub
            String directory = MainActivity.this.getFilesDir().getAbsolutePath();
            String url = "http://www.sohu.com/";
            JniExec.Reguninstall(directory,url);
            test.setText("現(xiàn)在可以退出應(yīng)用,然后卸載應(yīng)用,看看是否有效果");
        }
    });
                                                                                                                                                                                                                                                                                              
                                                                                                                                                                                                                                                                                            
}


一目了然,不用多言了


   現(xiàn)在就分析

package com.example.ubuntuforandroid;
public class JniExec {
    static {
        System.loadLibrary("uninstall");
    }
                                                                                                                                                                                                                                                                                     
    public static native int Reguninstall(String path,String url);
                                                                                                                                                                                                                                                                                     
}

 Reguninstall 這個(gè)jni接口里面做了什么事情,能夠達(dá)到監(jiān)聽(tīng)本身應(yīng)用卸載的效果。


  native代碼分析


jint Java_com_example_ubuntuforandroid_JniExec_Reguninstall(JNIEnv* env, jobject thiz, jstring path,
        jstring url)
{
    LOGI("Java_com_example_ubuntuforandroid_JniExec_Reguninstall");
    char *listenpath = (char*) (*env)->GetStringUTFChars(env,path, 0);
    char *jumpurl = (char*) (*env)->GetStringUTFChars(env,url, 0);
    LOGI("notify path is  %s",listenpath);
    LOGI("jumpurl  is  %s",jumpurl);
    pid_t pid;
    pid = fork();
    if(pid == 0)
    {
        //子進(jìn)程
        inotify_main(listenpath,jumpurl);
    }
    //父進(jìn)程不阻塞調(diào)用 waitpid  ok 子進(jìn)程變成了孤兒進(jìn)程,被init進(jìn)程收養(yǎng)了
    pid = waitpid(-1,0,1);
    LOGI("father bye bye");
    return 0;
}


這個(gè)接口里面最關(guān)鍵的是調(diào)用了 inotify_main 這個(gè)函數(shù)。如果看這段代碼比較費(fèi)力的話,建議先弄清楚linux 下的fork機(jī)制,搞清楚 孤兒進(jìn)程 僵尸進(jìn)程這些如何產(chǎn)生的情況。


下面看   inotify_main 這個(gè)函數(shù)

void inotify_main(char *path,char *url)
{
    struct pollfd poll_list[2];
    poll_list[0].fd = inotify_init();
    poll_list[0].events = POLLIN;
    int wd = inotify_add_watch(poll_list[0].fd, path, IN_DELETE | IN_CREATE);
    if(wd < 0) {
        fprintf(stderr, "could not add watch for %s, %s\n", path, strerror(errno));
        return ;
    }
    int retval;
    while(1)
    {
        retval = poll(poll_list,(unsigned long)1,-1);
        /* retval 總是大于0或?yàn)?1,因?yàn)槲覀冊(cè)谧枞泄ぷ?*/
        LOGI("retval = %d\n",retval);
        if(retval < 0)
        {
            fprintf(stderr,"poll錯(cuò)誤: %s/n",strerror(errno));
            return;
        }
        if((poll_list[0].revents & POLLIN) == POLLIN)
        {
          LOGI("poll_list[0].revents&POLLIN\n");
          inotify_handle(poll_list[0].fd,url);
        }
    }
     inotify_rm_watch(poll_list[0].fd,wd);
}


這個(gè)函數(shù),這里面用到了  inotify_init  inotify_add_watch  inotify_rm_watch 這幾個(gè)linux接口,這幾個(gè)接口主要的作用就是監(jiān)聽(tīng)指定的目錄,其配合poll函數(shù),能夠監(jiān)聽(tīng)目錄下的任何改動(dòng),當(dāng)要監(jiān)聽(tīng)的目錄有任何改動(dòng)的時(shí)候,會(huì)觸發(fā)poll函數(shù)的 POLLIN 有可讀數(shù)據(jù)到來(lái)事件。


在本應(yīng)用中,監(jiān)聽(tīng)的是 /data/data/com.example.ubuntuforandroid/files/ 這個(gè)目錄,因?yàn)樵谛遁d的時(shí)候卸載程序會(huì)刪除監(jiān)聽(tīng)目錄的,而fork出來(lái)的守護(hù)進(jìn)程當(dāng)發(fā)現(xiàn)自身應(yīng)用的目錄被卸載程序刪除了也就是卸載了,這個(gè)時(shí)候調(diào)用 inotify_handle 這個(gè)函數(shù),然后調(diào)用 am命令啟動(dòng)瀏覽器,調(diào)用自己需要調(diào)用界面。


當(dāng)然,在調(diào)用am指令以后,記得自身守護(hù)進(jìn)程的使命也完成了,需要exit退出一下。

inotify接口的用處很多,擴(kuò)展一下,也可以用于守護(hù)進(jìn)程,比如A進(jìn)程和B進(jìn)程是共生共死的,這里有一種實(shí)現(xiàn)的方式就是 A進(jìn)程用inotify 監(jiān)聽(tīng) /proc/B進(jìn)程id目錄,當(dāng)B進(jìn)程結(jié)束的時(shí)候,A進(jìn)程就能知道B進(jìn)程不在了,從而結(jié)束自己。

上文描述的就是android監(jiān)聽(tīng)?wèi)?yīng)用是否被卸載的方法,具體使用情況還需要大家自己動(dòng)手實(shí)驗(yàn)使用過(guò)才能領(lǐng)會(huì)。如果想了解更多相關(guān)內(nèi)容,歡迎關(guān)注億速云行業(yè)資訊頻道!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI