日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

Android 雙進(jìn)程守護(hù)嘗試與分析

 風(fēng)雪夜歸人_95 2015-03-26
       最近在做一個(gè)Android的項(xiàng)目,其包含一個(gè)消息推送的后臺(tái)服務(wù)。由于該服務(wù)可能會(huì)有重要的信息推送,因此并不希望當(dāng)APP程序退出、APP程序被一鍵清理、APP被強(qiáng)制停止等用戶操作發(fā)生時(shí),這個(gè)后臺(tái)服務(wù)也隨之被殺死。這個(gè)問題也就是所謂的“內(nèi)存永駐”。關(guān)于這個(gè)問題,網(wǎng)上有很多說(shuō)法,如調(diào)用startforehand函數(shù)以提高service的優(yōu)先級(jí)、在service中創(chuàng)建一個(gè)不能被刪掉的notification(或者產(chǎn)生一個(gè)其他的與用戶界面交互的UI控件)、在service的onDestroy函數(shù)中重啟這個(gè)服務(wù)、修改onstartcommand函數(shù)的返回值等等。這些方法,筆者都一一試過,但都沒有效果。但是,我們可以看到市面上也確實(shí)存在一些App在一定的時(shí)間后可以自動(dòng)重啟,說(shuō)明仍然是存在方法可以完成這項(xiàng)任務(wù)的。筆者在網(wǎng)上看到了這篇文章 http:///a/jingxuanboke/2014/0622/354671.html,覺得還是有些道理的。于是照著這個(gè)原理去做了。
       這篇文章中介紹的方法涉及到Android的JNI編程,主要思想就是通過調(diào)用native函數(shù)創(chuàng)建一個(gè)子進(jìn)程。父子進(jìn)程相互監(jiān)聽,若子進(jìn)程死去,父進(jìn)程妥善處理后重新創(chuàng)建新的子進(jìn)程;若父進(jìn)程死去,子進(jìn)程使用AM命令重啟父進(jìn)程。這種思想唯一的缺陷就是如何保證父子進(jìn)程不被同時(shí)殺死的情況。子進(jìn)程能不能被殺死,只能用實(shí)驗(yàn)來(lái)證明。
     首先筆者按照文章介紹的,整理了代碼,并將相關(guān)代碼植入到自己的項(xiàng)目中。
     步驟1)編寫Watcher類。它為上面的Java程序調(diào)用提供必要的接口,聲明需要native語(yǔ)言實(shí)現(xiàn)的的具體函數(shù)。native語(yǔ)言主要是指C/C++語(yǔ)言。上層的Java程序只需要?jiǎng)?chuàng)建一個(gè)Watcher類并調(diào)用它的createAppMonitor(String userId)函數(shù)即可。
 public class Watcher {
    private static final String PACKET = "com.example.dameonservice";
    private String mMonitoredService = "com.example.mqtt.MQTTSubscribeService";
    private volatile boolean bHeartBreak = false;
    private Context mContext;
    private boolean mRunning = true;
    
    public void createAppMonitor(String userId)
    {
        if(!createWatcher(userId))
        {
            Log.e("Watcher", "<<Monitor created failed>>");
        }
    }
    
    public Watcher(Context context)
    {
        mContext = context;
    }
  
    /*創(chuàng)建一個(gè)監(jiān)視子進(jìn)程
     *userId 當(dāng)前進(jìn)程的用戶ID,子進(jìn)程重啟當(dāng)前進(jìn)程時(shí)需要用到當(dāng)前進(jìn)程的用戶ID
     *return  若子進(jìn)程創(chuàng)建成功返回TRUE,否則返回FALSE
     */
    private native boolean createWatcher(String userId);
    
    /* 讓當(dāng)前進(jìn)程連接到監(jiān)視進(jìn)程
     * return 連接成功返回TRUE,否則返回FALSE
     */
    private native boolean connectToMonitor();
    
    /*向監(jiān)視進(jìn)程發(fā)送任意信息
     * msg 發(fā)給monitor的信息
     * return 實(shí)際發(fā)送的字節(jié)數(shù)
     */
    private native int sendMsgToMonitor(String msg);
    
    static
    {
        System.loadLibrary("monitor");   //這里要和后面的Android.mk中模塊名對(duì)應(yīng)
    }
}

2)編譯上面的文件會(huì)在bin/classes 目錄下生成相對(duì)應(yīng)的Watcher.class文件,通過DOs界面進(jìn)入該bin/classes 目錄下,通過javah命令生成C/C++對(duì)應(yīng)的頭文件。
“javah 包名+類名”   得到以下頭文件:
 #include <jni.h>
/* Header for class com_example_dameonservice_Watcher */

#ifndef _Included_com_example_dameonservice_Watcher
#define _Included_com_example_dameonservice_Watcher
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_example_dameonservice_Watcher
 * Method:    createWatcher
 * Signature: (Ljava/lang/String;)Z
 */
JNIEXPORT jboolean JNICALL Java_com_example_dameonservice_Watcher_createWatcher
  (JNIEnv *, jobject, jstring);

/*
 * Class:     com_example_dameonservice_Watcher
 * Method:    connectToMonitor
 * Signature: ()Z
 */
JNIEXPORT jboolean JNICALL Java_com_example_dameonservice_Watcher_connectToMonitor
  (JNIEnv *, jobject);

/*
 * Class:     com_example_dameonservice_Watcher
 * Method:    sendMsgToMonitor
 * Signature: (Ljava/lang/String;)I
 */
JNIEXPORT jint JNICALL Java_com_example_dameonservice_Watcher_sendMsgToMonitor
  (JNIEnv *, jobject, jstring);

#ifdef __cplusplus
}
#endif
#endif


3)創(chuàng)建JNI文件夾,將得到的頭文件移到該文件夾下,繼續(xù)在該文件夾下創(chuàng)建與上面得到的頭文件同名的C/C++文件,然后實(shí)現(xiàn)頭文件中提到的方法。(具體實(shí)現(xiàn)太多,這里就不再貼出來(lái)了)

4)添加Android.mk文件。這個(gè)文件的格式基本是統(tǒng)一的。只需要修改LOCAL_MODULELOCAL_SRC_FILES兩處即可。如果你還有添加Log打印函數(shù),還要在這里添加 “LOCAL_LDLIBS := -lm -llog”。

下面一張圖來(lái)說(shuō)明整體的文件結(jié)構(gòu)分布:
 其中com_example_dameonservice_Watcher.c和com_example_dameonservice_Watcher.cpp內(nèi)容相同。process.cpp定義一些輔助類。

實(shí)驗(yàn)結(jié)果:
       這當(dāng)然是大家最關(guān)心的。測(cè)試的手機(jī)選用的小米,感覺 小米在這一塊的優(yōu)化還是很不錯(cuò)的,所以用它來(lái)試試。最終的測(cè)試結(jié)果是:被殺死的服務(wù)概率性地可以重啟成功,且失敗的概率更大。通過Log分析,不能重啟的時(shí)候是因?yàn)樽舆M(jìn)程也死掉了。截止到筆者寫下這篇文章,還沒有抓住其中的規(guī)律。一鍵清理和子進(jìn)程的被殺死沒有絕對(duì)的對(duì)應(yīng)關(guān)系。而且即使是在App運(yùn)行的時(shí)候,也會(huì)發(fā)現(xiàn)子進(jìn)程會(huì)被殺死,然后又被父進(jìn)程重啟。子進(jìn)程被殺死是重啟失敗的主要原因。但現(xiàn)在的現(xiàn)象無(wú)法確定子進(jìn)程被殺死的確切原因,有一種可能是被系統(tǒng)殺死了,但這樣的不確定性太大,對(duì)效果也不能有很好的保證。
      雖然沒有完美解決問題,但至少比前面的辦法強(qiáng)很多,至少它也重啟成功過。這個(gè)方法感覺繼續(xù)優(yōu)化一下還是可以做好的。




    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多