Android進(jìn)程卑剩活方案

自己曾經(jīng)也在這個問題上傷過腦經(jīng),前幾日剛好有一個北京的哥們在QQ說在做IM類的項目摸柄,問我進(jìn)程辈罚活如何處理比較恰當(dāng),決定去總結(jié)一下塘幅,網(wǎng)上搜索一下進(jìn)程常駐的方案好多好多昔案,但是很多的方案都是不靠譜的或者不是最好的,結(jié)合很多資料电媳,今天總結(jié)一下Android進(jìn)程碧ごВ活的一些方案,都附有完整的實現(xiàn)源碼匾乓,有些可能你已經(jīng)知道捞稿,但是有些你可能是第一次聽說,

(1像素Activity拼缝,前臺服務(wù)娱局,賬號同步,Jobscheduler,相互喚醒咧七,系統(tǒng)服務(wù)捆綁衰齐,如果你都了解了,請忽略)經(jīng)過多方面的驗證继阻,Android系統(tǒng)中在沒有白名單的情況下做一個任何情況下都不被殺死的應(yīng)用是基本不可能的耻涛,但是我們可以做到我們的應(yīng)用基本不被殺死,如果殺死可以馬上滿血復(fù)活瘟檩,原諒我講的特別含蓄抹缕,畢竟現(xiàn)在的技術(shù)防不勝防啊,不死應(yīng)用還是可能的墨辛。

有幾個問題需要思考卓研,系統(tǒng)為什么會殺掉進(jìn)程,殺的為什么是我的進(jìn)程睹簇,這是按照什么標(biāo)準(zhǔn)來選擇的奏赘,是一次性干掉多個進(jìn)程,還是一個接著一個殺太惠,敝菊洌活套路一堆,如何進(jìn)行進(jìn)程倍膺叮活才是比較恰當(dāng)......如果這些問題你還還存在,或許這篇文章可以解答。

一嗽元、進(jìn)程初步了解

每一個Android應(yīng)用啟動后至少對應(yīng)一個進(jìn)程敛纲,有的是多個進(jìn)程,而且主流應(yīng)用中多個進(jìn)程的應(yīng)用比例較大


image.png

1剂癌、如何查看進(jìn)程解基本信息

對于任何一個進(jìn)程淤翔,我們都可以通過adb shell ps|grep <package_name>的方式來查看它的基本信息


image.png


[圖片上傳中...(image.png-afd0c1-1556955294471-0)]

2、進(jìn)程劃分

Android中的進(jìn)程跟封建社會一樣佩谷,分了三流九等旁壮,Android系統(tǒng)把進(jìn)程的劃為了如下幾種(重要性從高到低),網(wǎng)上多位大神都詳細(xì)總結(jié)過(備注:嚴(yán)格來說是劃分了6種)谐檀。

2.1抡谐、前臺進(jìn)程(Foreground process)

場景:

  • 某個進(jìn)程持有一個正在與用戶交互的Activity并且該Activity正處于resume的狀態(tài)。
  • 某個進(jìn)程持有一個Service桐猬,并且該Service與用戶正在交互的Activity綁定麦撵。
  • 某個進(jìn)程持有一個Service,并且該Service調(diào)用startForeground()方法使之位于前臺運行溃肪。
  • 某個進(jìn)程持有一個Service免胃,并且該Service正在執(zhí)行它的某個生命周期回調(diào)方法,比如onCreate()惫撰、 onStart()或onDestroy()羔沙。
  • 某個進(jìn)程持有一個BroadcastReceiver,并且該BroadcastReceiver正在執(zhí)行其onReceive()方法厨钻。
    用戶正在使用的程序扼雏,一般系統(tǒng)是不會殺死前臺進(jìn)程的,除非用戶強制停止應(yīng)用或者系統(tǒng)內(nèi)存不足等極端情況會殺死莉撇。

2.2呢蛤、可見進(jìn)程(Visible process)

場景:

  • 擁有不在前臺、但仍對用戶可見的 Activity(已調(diào)用 onPause())棍郎。
  • 擁有綁定到可見(或前臺)Activity 的 Service

用戶正在使用其障,看得到,但是摸不著涂佃,沒有覆蓋到整個屏幕,只有屏幕的一部分可見進(jìn)程不包含任何前臺組件励翼,一般系統(tǒng)也是不會殺死可見進(jìn)程的,除非要在資源吃緊的情況下辜荠,要保持某個或多個前臺進(jìn)程存活

2.3汽抚、服務(wù)進(jìn)程(Service process)

場景

  • 某個進(jìn)程中運行著一個Service且該Service是通過startService()啟動的,與用戶看見的界面沒有直接關(guān)聯(lián)伯病。

在內(nèi)存不足以維持所有前臺進(jìn)程和可見進(jìn)程同時運行的情況下造烁,服務(wù)進(jìn)程會被殺死

2.4、后臺進(jìn)程(Background process)

場景:

  • 在用戶按了"back"或者"home"后,程序本身看不到了,但是其實還在運行的程序,比如Activity調(diào)用了onPause方法

系統(tǒng)可能隨時終止它們惭蟋,回收內(nèi)存

2.5苗桂、空進(jìn)程(Empty process)

場景:

  • 某個進(jìn)程不包含任何活躍的組件時該進(jìn)程就會被置為空進(jìn)程,完全沒用,殺了它只有好處沒壞處,第一個干它!

3告组、內(nèi)存閾值

上面是進(jìn)程的分類煤伟,進(jìn)程是怎么被殺的呢?系統(tǒng)出于體驗和性能上的考慮木缝,app在退到后臺時系統(tǒng)并不會真正的kill掉這個進(jìn)程便锨,而是將其緩存起來。打開的應(yīng)用越多我碟,后臺緩存的進(jìn)程也越多放案。在系統(tǒng)內(nèi)存不足的情況下,系統(tǒng)開始依據(jù)自身的一套進(jìn)程回收機制來判斷要kill掉哪些進(jìn)程怎囚,以騰出內(nèi)存來供給需要的app, 這套殺進(jìn)程回收內(nèi)存的機制就叫 Low Memory Killer卿叽。那這個不足怎么來規(guī)定呢,那就是內(nèi)存閾值恳守,我們可以使用cat /sys/module/lowmemorykiller/parameters/minfree來查看某個手機的內(nèi)存閾值考婴。

image.png

注意這些數(shù)字的單位是page. 1 page = 4 kb.上面的六個數(shù)字對應(yīng)的就是(MB): 72,90,108,126,144,180,這些數(shù)字也就是對應(yīng)的內(nèi)存閥值,內(nèi)存閾值在不同的手機上不一樣催烘,一旦低于該值,Android便開始按順序關(guān)閉進(jìn)程. 因此Android開始結(jié)束優(yōu)先級最低的空進(jìn)程沥阱,即當(dāng)可用內(nèi)存小于180MB(46080*4/1024)。

讀到這里伊群,你或許有一個疑問考杉,假設(shè)現(xiàn)在內(nèi)存不足,空進(jìn)程都被殺光了舰始,現(xiàn)在要殺后臺進(jìn)程崇棠,但是手機中后臺進(jìn)程很多,難道要一次性全部都清理掉丸卷?當(dāng)然不是的枕稀,進(jìn)程是有它的優(yōu)先級的,這個優(yōu)先級通過進(jìn)程的adj值來反映谜嫉,它是linux內(nèi)核分配給每個系統(tǒng)進(jìn)程的一個值萎坷,代表進(jìn)程的優(yōu)先級,進(jìn)程回收機制就是根據(jù)這個優(yōu)先級來決定是否進(jìn)行回收沐兰,adj值定義在com.android.server.am.ProcessList類中哆档,這個類路徑是${android-sdk-path}sourcesandroid-23comandroidserveramProcessList.java。oom_adj的值越小住闯,進(jìn)程的優(yōu)先級越高瓜浸,普通進(jìn)程oom_adj值是大于等于0的澳淑,而系統(tǒng)進(jìn)程oom_adj的值是小于0的,我們可以通過cat /proc/進(jìn)程id/oom_adj可以看到當(dāng)前進(jìn)程的adj值斟叼。

image.png

看到adj值是0偶惠,0就代表這個進(jìn)程是屬于前臺進(jìn)程,我們按下Back鍵朗涩,將應(yīng)用至于后臺,再次查看

image.png

adj值變成了8绑改,8代表這個進(jìn)程是屬于不活躍的進(jìn)程谢床,你可以嘗試其他情況下,oom_adj值是多少厘线,但是每個手機的廠商可能不一樣识腿,oom_adj值主要有這么幾個,可以參考一下造壮。


123123.png

備注:(上表的數(shù)字可能在不同系統(tǒng)會有一定的出入)
根據(jù)上面的adj值渡讼,其實系統(tǒng)在進(jìn)程回收跟內(nèi)存回收類似也是有一套嚴(yán)格的策略,可以自己去了解耳璧,大概是這個樣子的成箫,oom_adj越大,占用物理內(nèi)存越多會被最先kill掉旨枯,OK蹬昌,那么現(xiàn)在對于進(jìn)程如何保活這個問題就轉(zhuǎn)化成攀隔,如何降低oom_adj的值皂贩,以及如何使得我們應(yīng)用占的內(nèi)存最少。

二昆汹、進(jìn)程泵魉ⅲ活方案

1、開啟一個像素的Activity

據(jù)說這個是手Q的進(jìn)程甭郑活方案辈末,基本思想,系統(tǒng)一般是不會殺死前臺進(jìn)程的败潦。所以要使得進(jìn)程常駐本冲,我們只需要在鎖屏的時候在本進(jìn)程開啟一個Activity,為了欺騙用戶劫扒,讓這個Activity的大小是1像素檬洞,并且透明無切換動畫,在開屏幕的時候沟饥,把這個Activity關(guān)閉掉添怔,所以這個就需要監(jiān)聽系統(tǒng)鎖屏廣播湾戳,我試過了,的確好使广料,如下砾脑。

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
   }
}

如果直接啟動一個Activity,當(dāng)我們按下back鍵返回桌面的時候艾杏,oom_adj的值是8韧衣,上面已經(jīng)提到過,這個進(jìn)程在資源不夠的情況下是容易被回收的」荷#現(xiàn)在造一個一個像素的Activity畅铭。

public class LiveActivity extends Activity {

    public static final String TAG = LiveActivity.class.getSimpleName();

    public static void actionToLiveActivity(Context pContext) {
        Intent intent = new Intent(pContext, LiveActivity.class);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        pContext.startActivity(intent);
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d(TAG, "onCreate");
        setContentView(R.layout.activity_live);

        Window window = getWindow();
        //放在左上角
        window.setGravity(Gravity.START | Gravity.TOP);
        WindowManager.LayoutParams attributes = window.getAttributes();
        //寬高設(shè)計為1個像素
        attributes.width = 1;
        attributes.height = 1;
        //起始坐標(biāo)
        attributes.x = 0;
        attributes.y = 0;
        window.setAttributes(attributes);

        ScreenManager.getInstance(this).setActivity(this);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.d(TAG, "onDestroy");
    }
}

為了做的更隱藏,最好設(shè)置一下這個Activity的主題勃蜘,當(dāng)然也無所謂了

   <style name="LiveStyle">
        <item name="android:windowIsTranslucent">true</item>
        <item name="android:windowBackground">@android:color/transparent</item>
        <item name="android:windowAnimationStyle">@null</item>
        <item name="android:windowNoTitle">true</item>
   </style>

在屏幕關(guān)閉的時候把LiveActivity啟動起來硕噩,在開屏的時候把LiveActivity 關(guān)閉掉,所以要監(jiān)聽系統(tǒng)鎖屏廣播缭贡,以接口的形式通知MainActivity啟動或者關(guān)閉LiveActivity炉擅。

public class ScreenBroadcastListener {

    private Context mContext;

    private ScreenBroadcastReceiver mScreenReceiver;

    private ScreenStateListener mListener;

    public ScreenBroadcastListener(Context context) {
        mContext = context.getApplicationContext();
        mScreenReceiver = new ScreenBroadcastReceiver();
    }

    interface ScreenStateListener {

        void onScreenOn();

        void onScreenOff();
    }

    /**
     * screen狀態(tài)廣播接收者
     */
    private class ScreenBroadcastReceiver extends BroadcastReceiver {
        private String action = null;

        @Override
        public void onReceive(Context context, Intent intent) {
            action = intent.getAction();
            if (Intent.ACTION_SCREEN_ON.equals(action)) { // 開屏
                mListener.onScreenOn();
            } else if (Intent.ACTION_SCREEN_OFF.equals(action)) { // 鎖屏
                mListener.onScreenOff();
            }
        }
    }

    public void registerListener(ScreenStateListener listener) {
        mListener = listener;
        registerListener();
    }

    private void registerListener() {
        IntentFilter filter = new IntentFilter();
        filter.addAction(Intent.ACTION_SCREEN_ON);
        filter.addAction(Intent.ACTION_SCREEN_OFF);
        mContext.registerReceiver(mScreenReceiver, filter);
    }
}

public class ScreenManager {

    private Context mContext;

    private WeakReference<Activity> mActivityWref;

    public static ScreenManager gDefualt;

    public static ScreenManager getInstance(Context pContext) {
        if (gDefualt == null) {
            gDefualt = new ScreenManager(pContext.getApplicationContext());
        }
        return gDefualt;
    }
    private ScreenManager(Context pContext) {
        this.mContext = pContext;
    }

    public void setActivity(Activity pActivity) {
        mActivityWref = new WeakReference<Activity>(pActivity);
    }

    public void startActivity() {
            LiveActivity.actionToLiveActivity(mContext);
    }

    public void finishActivity() {
        //結(jié)束掉LiveActivity
        if (mActivityWref != null) {
            Activity activity = mActivityWref.get();
            if (activity != null) {
                activity.finish();
            }
        }
    }
}


現(xiàn)在MainActivity改成如下

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        final ScreenManager screenManager = ScreenManager.getInstance(MainActivity.this);
        ScreenBroadcastListener listener = new ScreenBroadcastListener(this);
         listener.registerListener(new ScreenBroadcastListener.ScreenStateListener() {
            @Override
            public void onScreenOn() {
                screenManager.finishActivity();
            }

            @Override
            public void onScreenOff() {
                screenManager.startActivity();
            }
        });
    }
}


按下back之后,進(jìn)行鎖屏阳惹,現(xiàn)在測試一下oom_adj的值


image.png

果然將進(jìn)程的優(yōu)先級提高了谍失。

但是還有一個問題,內(nèi)存也是一個考慮的因素穆端,內(nèi)存越多會被最先kill掉袱贮,所以把上面的業(yè)務(wù)邏輯放到Service中,而Service是在另外一個 進(jìn)程中体啰,在MainActivity開啟這個服務(wù)就行了攒巍,這樣這個進(jìn)程就更加的輕量,

public class LiveService extends Service {

    public  static void toLiveService(Context pContext){
        Intent intent=new Intent(pContext,LiveService.class);
        pContext.startService(intent);
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        //屏幕關(guān)閉的時候啟動一個1像素的Activity荒勇,開屏的時候關(guān)閉Activity
        final ScreenManager screenManager = ScreenManager.getInstance(LiveService.this);
        ScreenBroadcastListener listener = new ScreenBroadcastListener(this);
        listener.registerListener(new ScreenBroadcastListener.ScreenStateListener() {
            @Override
            public void onScreenOn() {
                screenManager.finishActivity();
            }
            @Override
            public void onScreenOff() {
                screenManager.startActivity();
            }
        });
        return START_REDELIVER_INTENT;
    }
}

      <service android:name=".LiveService"
            android:process=":live_service"/>

OK柒莉,通過上面的操作,我們的應(yīng)用就始終和前臺進(jìn)程是一樣的優(yōu)先級了沽翔,為了省電兢孝,系統(tǒng)檢測到鎖屏事件后一段時間內(nèi)會殺死后臺進(jìn)程,如果采取這種方案仅偎,就可以避免了這個問題跨蟹。但是還是有被殺掉的可能,所以我們還需要做雙進(jìn)程守護(hù)橘沥,關(guān)于雙進(jìn)程守護(hù)窗轩,比較適合的就是aidl的那種方式,但是這個不是完全的靠譜座咆,原理是A進(jìn)程死的時候痢艺,B還在活著仓洼,B可以將A進(jìn)程拉起來,反之堤舒,B進(jìn)程死的時候色建,A還活著,A可以將B拉起來舌缤。所以雙進(jìn)程守護(hù)的前提是箕戳,系統(tǒng)殺進(jìn)程只能一個個的去殺,如果一次性殺兩個友驮,這種方法也是不OK的漂羊。

事實上
那么我們先來看看Android5.0以下的源碼,ActivityManagerService是如何關(guān)閉在應(yīng)用退出后清理內(nèi)存的

Process.killProcessQuiet(pid);  

應(yīng)用退出后卸留,ActivityManagerService就把主進(jìn)程給殺死了,但是椭豫,在Android5.0以后耻瑟,ActivityManagerService卻是這樣處理的:

Process.killProcessQuiet(app.pid);  
Process.killProcessGroup(app.info.uid, app.pid);  

在應(yīng)用退出后,ActivityManagerService不僅把主進(jìn)程給殺死赏酥,另外把主進(jìn)程所屬的進(jìn)程組一并殺死,這樣一來,由于子進(jìn)程和主進(jìn)程在同一進(jìn)程組老虫,子進(jìn)程在做的事情更鲁,也就停止了。所以在Android5.0以后的手機應(yīng)用在進(jìn)程被殺死后呵晨,要采用其他方案魏保。

2、前臺服務(wù)

摸屠,這方案實際利用了Android前臺service的漏洞谓罗。原理如下對于 API level < 18 :調(diào)用startForeground(ID, new Notification())季二,發(fā)送空的Notification 檩咱,圖標(biāo)則不會顯示。對于 API level >= 18:在需要提優(yōu)先級的service A啟動一個InnerService胯舷,兩個服務(wù)同時startForeground刻蚯,且綁定同樣的 ID。Stop 掉InnerService 桑嘶,這樣通知欄圖標(biāo)即被移除炊汹。

public class KeepLiveService extends Service {

    public static final int NOTIFICATION_ID=0x11;

    public KeepLiveService() {
    }

    @Override
    public IBinder onBind(Intent intent) {
        throw new UnsupportedOperationException("Not yet implemented");
    }

    @Override
    public void onCreate() {
        super.onCreate();
         //API 18以下,直接發(fā)送Notification并將其置為前臺
        if (Build.VERSION.SDK_INT <Build.VERSION_CODES.JELLY_BEAN_MR2) {
            startForeground(NOTIFICATION_ID, new Notification());
        } else {
            //API 18以上不翩,發(fā)送Notification并將其置為前臺后兵扬,啟動InnerService
            Notification.Builder builder = new Notification.Builder(this);
            builder.setSmallIcon(R.mipmap.ic_launcher);
            startForeground(NOTIFICATION_ID, builder.build());
            startService(new Intent(this, InnerService.class));
        }
    }

    public  static class  InnerService extends Service{
        @Override
        public IBinder onBind(Intent intent) {
            return null;
        }
        @Override
        public void onCreate() {
            super.onCreate();
            //發(fā)送與KeepLiveService中ID相同的Notification麻裳,然后將其取消并取消自己的前臺顯示
            Notification.Builder builder = new Notification.Builder(this);
            builder.setSmallIcon(R.mipmap.ic_launcher);
            startForeground(NOTIFICATION_ID, builder.build());
            new Handler().postDelayed(new Runnable() {
                @Override
                public void run() {
                    stopForeground(true);
                    NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
                    manager.cancel(NOTIFICATION_ID);
                    stopSelf();
                }
            },100);

        }
    }
}

在沒有采取前臺服務(wù)之前,啟動應(yīng)用器钟,oom_adj值是0津坑,按下返回鍵之后,變成9(不同ROM可能不一樣)


image.png

在采取前臺服務(wù)之后傲霸,啟動應(yīng)用疆瑰,oom_adj值是0,按下返回鍵之后昙啄,變成2(不同ROM可能不一樣)穆役,確實進(jìn)程的優(yōu)先級有所提高。


image.png

3梳凛、相互喚醒

相互喚醒的意思就是耿币,假如你手機里裝了支付寶、淘寶韧拒、天貓淹接、UC等阿里系的app,那么你打開任意一個阿里系的app后叛溢,有可能就順便把其他阿里系的app給喚醒了塑悼。這個完全有可能的。此外楷掉,開機厢蒜,網(wǎng)絡(luò)切換、拍照烹植、拍視頻時候斑鸦,利用系統(tǒng)產(chǎn)生的廣播也能喚醒app,不過Android N已經(jīng)將這三種廣播取消了刊橘。

image.png

image.png

如果應(yīng)用想北刹牛活,要是QQ促绵,微信愿意救你也行攒庵,有多少手機上沒有QQ,微信呢败晴?或者像友盟浓冒,信鴿這種推送SDK,也存在喚醒app的功能尖坤。
拉活方法

4稳懒、JobSheduler

JobSheduler是作為進(jìn)程死后復(fù)活的一種手段,native進(jìn)程方式最大缺點是費電慢味, Native 進(jìn)程費電的原因是感知主進(jìn)程是否存活有兩種實現(xiàn)方式场梆,在 Native 進(jìn)程中通過死循環(huán)或定時器墅冷,輪訓(xùn)判斷主進(jìn)程是否存活,當(dāng)主進(jìn)程不存活時進(jìn)行拉活或油。其次5.0以上系統(tǒng)不支持寞忿。 但是JobSheduler可以替代在Android5.0以上native進(jìn)程方式,這種方式即使用戶強制關(guān)閉顶岸,也能被拉起來腔彰,親測可行。

  JobSheduler@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public class MyJobService extends JobService {
    @Override
    public void onCreate() {
        super.onCreate();
        startJobSheduler();
    }

    public void startJobSheduler() {
        try {
            JobInfo.Builder builder = new JobInfo.Builder(1, new ComponentName(getPackageName(), MyJobService.class.getName()));
            builder.setPeriodic(5);
            builder.setPersisted(true);
            JobScheduler jobScheduler = (JobScheduler) this.getSystemService(Context.JOB_SCHEDULER_SERVICE);
            jobScheduler.schedule(builder.build());
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    @Override
    public boolean onStartJob(JobParameters jobParameters) {
        return false;
    }

    @Override
    public boolean onStopJob(JobParameters jobParameters) {
        return false;
    }
}

5辖佣、粘性服務(wù)&與系統(tǒng)服務(wù)捆綁

這個是系統(tǒng)自帶的霹抛,onStartCommand方法必須具有一個整形的返回值,這個整形的返回值用來告訴系統(tǒng)在服務(wù)啟動完畢后卷谈,如果被Kill杯拐,系統(tǒng)將如何操作,這種方案雖然可以世蔗,但是在某些情況or某些定制ROM上可能失效藕施,我認(rèn)為可以多做一種保保守方案。

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    return START_REDELIVER_INTENT;
}

  • START_STICKY
    如果系統(tǒng)在onStartCommand返回后被銷毀凸郑,系統(tǒng)將會重新創(chuàng)建服務(wù)并依次調(diào)用onCreate和onStartCommand(注意:根據(jù)測試Android2.3.3以下版本只會調(diào)用onCreate根本不會調(diào)用onStartCommand,Android4.0可以辦到)矛市,這種相當(dāng)于服務(wù)又重新啟動恢復(fù)到之前的狀態(tài)了)芙沥。
  • START_NOT_STICKY
    如果系統(tǒng)在onStartCommand返回后被銷毀,如果返回該值浊吏,則在執(zhí)行完onStartCommand方法后如果Service被殺掉系統(tǒng)將不會重啟該服務(wù)而昨。
  • START_REDELIVER_INTENT
    START_STICKY的兼容版本,不同的是其不保證服務(wù)被殺后一定能重啟找田。

這里說的系統(tǒng)服務(wù)很好理解歌憨,比如NotificationListenerService,NotificationListenerService就是一個監(jiān)聽通知的服務(wù)墩衙,只要手機收到了通知务嫡,NotificationListenerService都能監(jiān)聽到,即時用戶把進(jìn)程殺死漆改,也能重啟心铃,所以說要是把這個服務(wù)放到我們的進(jìn)程之中,那么就可以呵呵了

@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
public class LiveService extends NotificationListenerService {

    public LiveService() {

    }

    @Override
    public void onNotificationPosted(StatusBarNotification sbn) {
    }

    @Override
    public void onNotificationRemoved(StatusBarNotification sbn) {
    }
}

但是這種方式需要權(quán)限

  <service
            android:name=".LiveService"
            android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
            <intent-filter>
                <action android:name="android.service.notification.NotificationListenerService" />
            </intent-filter>
        </service>

所以你的應(yīng)用要是有消息推送的話挫剑,那么可以用這種方式去欺騙用戶去扣。

喜歡請點擊+關(guān)注哦

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市樊破,隨后出現(xiàn)的幾起案子愉棱,更是在濱河造成了極大的恐慌唆铐,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,406評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件奔滑,死亡現(xiàn)場離奇詭異艾岂,居然都是意外死亡,警方通過查閱死者的電腦和手機档押,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,732評論 3 393
  • 文/潘曉璐 我一進(jìn)店門澳盐,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人令宿,你說我怎么就攤上這事叼耙。” “怎么了粒没?”我有些...
    開封第一講書人閱讀 163,711評論 0 353
  • 文/不壞的土叔 我叫張陵筛婉,是天一觀的道長。 經(jīng)常有香客問我癞松,道長爽撒,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,380評論 1 293
  • 正文 為了忘掉前任响蓉,我火速辦了婚禮硕勿,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘枫甲。我一直安慰自己源武,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,432評論 6 392
  • 文/花漫 我一把揭開白布想幻。 她就那樣靜靜地躺著粱栖,像睡著了一般。 火紅的嫁衣襯著肌膚如雪脏毯。 梳的紋絲不亂的頭發(fā)上闹究,一...
    開封第一講書人閱讀 51,301評論 1 301
  • 那天,我揣著相機與錄音食店,去河邊找鬼渣淤。 笑死,一個胖子當(dāng)著我的面吹牛叛买,可吹牛的內(nèi)容都是我干的砂代。 我是一名探鬼主播,決...
    沈念sama閱讀 40,145評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼率挣,長吁一口氣:“原來是場噩夢啊……” “哼刻伊!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,008評論 0 276
  • 序言:老撾萬榮一對情侶失蹤捶箱,失蹤者是張志新(化名)和其女友劉穎智什,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體丁屎,經(jīng)...
    沈念sama閱讀 45,443評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡荠锭,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,649評論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了晨川。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片证九。...
    茶點故事閱讀 39,795評論 1 347
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖共虑,靈堂內(nèi)的尸體忽然破棺而出愧怜,到底是詐尸還是另有隱情,我是刑警寧澤妈拌,帶...
    沈念sama閱讀 35,501評論 5 345
  • 正文 年R本政府宣布拥坛,位于F島的核電站,受9級特大地震影響尘分,放射性物質(zhì)發(fā)生泄漏猜惋。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,119評論 3 328
  • 文/蒙蒙 一培愁、第九天 我趴在偏房一處隱蔽的房頂上張望著摔。 院中可真熱鬧,春花似錦定续、人聲如沸梨撞。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,731評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至时肿,卻和暖如春庇茫,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背螃成。 一陣腳步聲響...
    開封第一講書人閱讀 32,865評論 1 269
  • 我被黑心中介騙來泰國打工旦签, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人寸宏。 一個月前我還...
    沈念sama閱讀 47,899評論 2 370
  • 正文 我出身青樓宁炫,卻偏偏與公主長得像,于是被迫代替她去往敵國和親氮凝。 傳聞我的和親對象是個殘疾皇子羔巢,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,724評論 2 354

推薦閱讀更多精彩內(nèi)容

  • 自己曾經(jīng)也在這個問題上傷過腦經(jīng)竿秆,前幾日剛好有一個北京的哥們在QQ說在做IM類的項目启摄,問我進(jìn)程保活如何處理比較恰當(dāng)幽钢,...
    4e70992f13e7閱讀 3,769評論 9 158
  • 自己曾經(jīng)也在這個問題上傷過腦經(jīng)匪燕,前幾日剛好有一個北京的哥們在QQ說在做IM類的項目蕾羊,問我進(jìn)程保活如何處理比較恰當(dāng)帽驯,...
    Android高級開發(fā)閱讀 1,215評論 0 15
  • 目的 進(jìn)程苯缋梗活是各個公司想要實現(xiàn)的一個功能吸申,可以“無賴”地一直霸占你的手機,不被系統(tǒng)和第三方殺掉享甸,以下是幾種方案截碴,...
    Eren丶耶格爾閱讀 740評論 0 21
  • 如何進(jìn)行進(jìn)程比盏ぃ活,首先我們應(yīng)該先分析一下進(jìn)程被殺死的原因開始 Android進(jìn)程被殺死的場景分析: 從 Andro...
    如穎隨行日記閱讀 4,911評論 2 4