Android守護進程


這幾天,一位做Android的朋友和我探討了一個問題:因為業務需求的原因,在自己的App長時間不使用被kill掉之后,如何讓它再重新運行起來。

雖然,我本身很排斥這種做法,有點類似“流氓軟件”的行為,但是還是查詢了資料,大概想了一個實現的方式,和大家一起分享。

其實,這個問題可以簡單的看作:如何編寫一個守護進程

使用C/C++編寫一個守護進程的.so程序,Android端通過JNI調用。該進程監聽當前的目標程序進程,如果目標程序被kill掉了,再重新start一下,大概的思路就是這樣。偽代碼如下:

int pid = fork();
if(pid <0)
{    
    printf("Error\n");
    exit(0);
}
else if(pid > 0)
{
    printf("this is father\n");
    exit(0);
}
else if(pid == 0) // child1
{
    setsid();
    int pid = fork();
    if(pid  == 0) // child2
    {
        while(1)
        {
            if(App is killed)
                start App again;
        }
    }
}

這其中,缺少了:

①unmask(),因為從父進程繼承下來了一些東西,所以需要設置一定的權限進行操作。

②chdir("/")。

③關閉從父進程繼承而來的不需要的文件描述符,否則就可能造成資源的浪費。

為什么要進行兩次fork()?

在這段偽代碼中,進行了兩次fork()操作,其實很多文章在描述守護進程時都只是僅僅的進行了一次fork操作就結束了,這里我想仔細講一講原因。

首先,setsid()函數的作用。一般而言,父進程和子進程都處在一個session當中,父進程是session的領頭進程。如果當父進程(領頭進程)被殺死之后,那么同一個session中的所有進程都會被殺死,或者成為孤兒進程而被init托管。所以,我們需要讓子進程調用setsid(),創建一個新的session並將自己設置為該session的領頭進程(若領頭進程調用setsid()則沒有任何效果)。這樣,如果父進程被kill掉,因為他們並不在一個session中,所以子進程仍然可以繼續執行。由於session對控制終端的獨占性,進程同時與控制終端脫離。

session中包含了很多東西,如:控制終端、進程組等等。如果我們只fork()一次,將第一個由父進程創建出的子進程分離出來作為守護進程,一般情況下也是沒有什么問題的。但是,如果此時通過什么方式通過此進程創建出了一個與自己的session相關聯的控制終端,那么則會產生一定的影響。所以,則有了第二次fork()的意義。第二次fork使用子進程創建出了一個“孫子進程”,並且我們還是使用第一個父進程創建出的子進程進行setsid()但它並不是守護進程,該孫子進程進行守護進程相關的操作。這就有效的避免了上文提到的問題的產生,因為子進程創建出了一個新的session,並且作為該session的領頭進程,同時這個session包含了該孫子進程且它並不是領頭進程。那么該孫子進程就永遠無法創建出一個控制終端,也就沒有任何影響。

存在的問題

代碼中使用輪詢的方式來查詢,App進程是否被kill了,這樣效率十分低下,會導致手機的電量損耗很快。是否可以通過進程間通信的方式,如:socket等等,進行相關操作。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM