小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

Android service 不被殺死“永不退出的服務(wù)”(雙進程,服務(wù),多進程,微信)

 liang1234_ 2019-02-03

本文的應(yīng)用部分使用藍色表示


介紹服務(wù)開發(fā):

 

介紹關(guān)于服務(wù)不被殺死,以及微信的永久駐村謎底;

第一次做關(guān)于服務(wù)的開發(fā),看了很多文章,終于有個大概,任后開始寫程序測試并感受。在這里把學(xué)到的東西匯總一下,分享給大家。

 

隨便一搜索很對關(guān)于Android開發(fā)service的文章,所以這簡要說明。有一篇文章說的很好:“它是一種長生命周期的,沒有可視化界面,運行于后臺的一種服務(wù)程序。比如我們播放音樂的 時候,有可能想邊聽音樂邊干些其他事情,當退出播放音樂的應(yīng)用,如果不用Service,我 們就聽不到歌了,所以這時候就得用到Service了?!?/p>

我喜歡這個解釋。當然除此之外,普通應(yīng)用使用了service使得整個應(yīng)用有好的耦合性(功能實現(xiàn)不互相依靠,相對比較獨立)。就從字面意思來理解,提供服務(wù)的功能部分一般適合開發(fā)成一個服務(wù)。比如藍牙連接服務(wù)。網(wǎng)絡(luò)通信服務(wù)。音樂播放服務(wù)。當然我們自己開發(fā)的服務(wù)一般只給自己的應(yīng)用使用。

 

以下簡單匯總一下其他文章提到的精華部分,以及不全其他文章不足的地方。

1.Android service分類:startservice bindservice兩種方式。

startservice適合服務(wù)與應(yīng)用程序在一塊的情況,service和調(diào)用的應(yīng)用程序在同一個進程里面。一般用于執(zhí)行更新,加載等費事的操作。

Bindservice適用于完成一個獨立功能的部分。不如一個藍牙服務(wù),需要藍牙服務(wù)的app只需要bind服務(wù)就可以使用這個服務(wù),相對于startservice來說,bindservice給更多調(diào)用者服務(wù)。

生命周期,網(wǎng)上文章說,startservice調(diào)用者不在了,還可以繼續(xù)執(zhí)行,

而,bindservice可以支持好多調(diào)用者綁定,當時一旦所有綁定者都死掉的化,bindservice也就退出了。當然startservice調(diào)用的時候會啟動服務(wù),bindservice在調(diào)用的時候如果服務(wù)還沒有被啟動則會啟動服務(wù)。我在實際測試中,只要用清理工具清理了調(diào)用服務(wù)的軟件,調(diào)用者不在了,無論那種方式啟動的服務(wù)都會被關(guān)閉。

 

下面專門說一下“永不退出的服務(wù)”

 

為了本文方便描述:先介紹測試中用到的兩種關(guān)閉服務(wù)的方法:

在用使用清理運行軟件的功能作為關(guān)閉服務(wù)的第一種測試方法:向側(cè)面滑動應(yīng)用就被關(guān)閉。即清理后臺運行的軟件。

在測試時關(guān)閉服務(wù)的第二種測試方式:在“正在運行的軟件”里點擊停止

關(guān)于周期網(wǎng)上有好多文章都是提到了“不死的服務(wù)”。很多文章提到了做出一個不死的服務(wù)。具體提到的方式有:

onStartCommand方法,返回START_STICKY

也就是在service的onstartcommand函數(shù)里返回這個值

@Override  

public int onStartCommand(Intent intent, int flags, int startId) {  

    flags = START_STICKY;  

    return super.onStartCommand(intent, flags, startId);  

}  

 

這個時候如果清理的是一個設(shè)置了START_STICKY的app,用方法一和二的時候服務(wù)都會被殺掉,后來我測試多了,發(fā)現(xiàn)在清理軟件里吧這個應(yīng)用加入白名單之后。在使用方法一的時候。acrivity被清理掉了,但是服務(wù)不會被清理。,使用方法二的時候,服務(wù)會被關(guān)閉,然后一段時間又會重新自動出現(xiàn)。即START_STICKY產(chǎn)生的效果。


1. 設(shè)置服務(wù)為前臺進程。startForeground(0x111, notification);具體操作過程查看其他文章。這里說一下效果,實現(xiàn)了前臺進程其實就是在狀態(tài)欄顯示一個提示,應(yīng)該是用來告訴用戶所執(zhí)行的動作在后臺還在進行者,只能說service的優(yōu)先級提高了,在系統(tǒng)內(nèi)存不足的時候不會被第一個銷毀。但是用戶是可以通過方法一和二關(guān)閉這個服務(wù)的。(即調(diào)用者死掉,其服務(wù)也會被殺掉)。

在service的ondestroy里發(fā)送開啟服務(wù)的intent。以及開啟兩個service相互監(jiān)視,誰死掉就發(fā)送intent啟動誰。本人沒有測試。由于看清了服務(wù)的一些使用特性,覺得開發(fā)這樣死活關(guān)不掉的應(yīng)用實在是不好。

還有就是要做成系統(tǒng)應(yīng)用,即把手機開啟root賬號,然后安裝app到系統(tǒng)到system/app目錄下。以使app獲取系統(tǒng)級別的啟動權(quán)限。

 

還有人為了達到不是服務(wù)真是用心良苦。居然研究了從linux底層開啟進程做起,因為是看到像微信,搜狐。說實話,很佩服這些人的頭腦以及技術(shù)。

以下這三篇文章講的很好關(guān)于這方面。

http://blog.csdn.net/ztemt_sw2/article/details/27101681

http://download.csdn.net/detail/mihang2/9283985

http://blog.csdn.net/huaxun66/article/details/53158162

 

總結(jié)一下自己為啥放棄開發(fā)一個不死的服務(wù)。

1. 需求方面:只有我的軟件在運行的時候,我的服務(wù)才有存在的必要。

2. 我用的是魅族和華為手機做的測試,使用清理后臺應(yīng)用(即:測試方法一)只要activity被殺死,那么跟著其對應(yīng)的service也被殺死,對于網(wǎng)上來說的很多實現(xiàn)不被殺死方法都是因為其測試用的手機系統(tǒng)比較原生,一般不會強制殺死一個沒有被調(diào)用的服務(wù)。當然我也沒有在模擬器里運行測試,就是在兩個手機上運行測試,是這樣的。

3. 發(fā)現(xiàn)微信也不是不死的app。發(fā)現(xiàn)酷狗音樂這種播放音樂的軟件也會在activity死掉的時候,停止播放音樂。

4. 關(guān)于用戶體驗的思考。對于普通應(yīng)用沒有必要在關(guān)閉activity之后仍然運行service。

關(guān)于要不要開啟一個不死的服務(wù):看到了一片英文文章,關(guān)于要不要做一個不死服務(wù)的必要性講的很好。

原文如下:

 

Diamonds Are Forever. ServicesAre Not.

By AndroidGuys

Android offers a “service” component. Unlike “activities”(screens) that interact directly with the user, services are more for managingbackground operations. The quintessential example is a music player, continuingto play tunes while its UI is not running.

Some developers then make the leap from “it is possible” to “itis a really good idea and should be used wherever”. Many people on AndroidGoogle Groups or StackOverflow propose to create services that “run forever”and ask how to prevent them from being killed off, and such.

These developers appear to ignore the costs of this approach:

·        While running, a serviceconsumes one process’ worth of memory, which is a substantial chunk, despiteDalvik’s heavy use of copy-on-write techniques to share memory betweenprocesses. A single service hogging memory is not that big of a deal; a dozensuch services will prevent the Android device from being usable. Hence, even ifthe memory footprint does not impact the developer directly, it impacts theusers indirectly — much like how pollution benefits the polluter with acorresponding cost to society.

·        While running, the servicewill need to fight Android, which will want to shut down the service if RAMgets too tight. While Android should, in principle, restart the service oncememory is plentiful again, the developer will have no control over the timingof this.

·        While running, the servicewill need to fight its own users, who may elect to shut down the service viathe Manage Applications screen, or through a third-party task manager. In thiscase, Android will not restart the service automatically.

·        The service will fall asleepwhen the device falls asleep and shuts down the CPU, which means even if theservice “runs forever”, it will not be able to run forever, unless it prevents the CPUfrom stopping, which wrecks battery life.

The recommended alternative is to use AlarmManager, as describedin a previous post and in finer Android programming books. Think of yourAndroid service as a cron job or Windows scheduled task, not as a persistentdaemon or Windows service. This approach works much better with Android’sframework and device limitations:

·        The service only uses memorywhen it is actually doing something, not just sitting around waiting.

·        The odds that Android willneed to kill off the service decreases, in part because the service will not be“old” and other services are likely to be killed first.

·        The odds that the user willneed to kill off the service decreases, because the service is less likely tocause any pollution that may cause the user problems.

·        The service can hold aWakeLock for the duration of its bit of work to keep the CPU running for ashort period

Now, the AlarmManager API is not the friendliest. Somedevelopers get tripped up while trying to handle multiple outstanding alarms.While there are ways to deal with this (via careful construction ofPendingIntent objects), sometimes you do not truly need more than one alarm. Ifyou have code that you want to run every 15 minutes, and other code that youwant to run every 24 hours, use one 15-minute alarm and trigger theonce-every-24-hours code every 96th time the 15-minute alarm goes off.

I encourage Android developers to try to avoid long-runningservices wherever possible. If you are uncertain how to design an app to avoidthe long-running service, post a clear description of the business scenario(not just low-level technical stuff) to the [android-developers] group or to StackOverflow with the #android tag. We can try to help you find ways ofachieving your business objectives in an Android-friendly fashion.


原文大體翻譯如下:

很多開發(fā)者為了達到服務(wù)隨時被啟動起來的activity調(diào)用,而忽略了以下這些消耗:

在運行的時候,盡管dalvik使用了用時復(fù)制技術(shù)來共享相同的內(nèi)存。但是一個存留的服務(wù)耗費了一個進程所占用的內(nèi)存。

在運行的時候,RAM耗盡的時候,服務(wù)仍然對抗android系統(tǒng)不讓殺掉自己

在運行的時候,服務(wù)要對抗關(guān)閉它的用戶。(用戶用應(yīng)用管理器或第三方管理器)

在運行的時候,當設(shè)備睡眠的時候,CPU被關(guān)閉。即服務(wù)也被關(guān)閉了,除非這個服務(wù)開啟阻擋手機睡眠選項。這就意味著電池電量的消耗。

 

因此推薦的方法是:使用AlarmManager。把你的服務(wù)當成定時執(zhí)行任務(wù)或者計劃執(zhí)行任務(wù)。而不是一個永久的服務(wù)就像windows服務(wù)那樣。

以下這樣的設(shè)計方法會是的應(yīng)用更好的與android系統(tǒng)構(gòu)架和諧并存。

1.    只有服務(wù)真的在做事情的時候才開啟服務(wù),不要讓服務(wù)坐著干等

2.    其實android殺死服務(wù)的幾率很低。因為只要你正在使用服務(wù),服務(wù)就不會變老。系統(tǒng)也就會殺掉其他服務(wù)而不是你正在使用的服務(wù)。

3.    用戶停掉服務(wù)的幾率也在減少。因為一個好的服務(wù)不會給用戶造成影響,也不會給用戶導(dǎo)致問題。

4.    服務(wù)在其工作期間可以使用一段時間的WakeLock來保持CPU保持運作。但用完時候馬上停用WakeLock。

我鼓勵android開發(fā)者在可能的情況下盡量避免開發(fā)長時間運行的服務(wù)。

以上是原文精華。

 

那么說這樣設(shè)計的例子有哪些。下面我舉“酷狗音樂”的例子。

當你打開“酷狗音樂”并且播放了一首音樂,音樂在播放,你按下home鍵,然后activity被放置在后天,這個時候,后臺服務(wù)來播放音樂。在播放的時候會在消息欄顯示一個正在播放的音樂狀態(tài),以及控制按鈕,這個部分是把服務(wù)設(shè)置為前臺服務(wù)。提高了服務(wù)的優(yōu)先級。那么現(xiàn)在你使用我上面說的方法一,即把“酷狗音樂”的activity真正關(guān)閉之后,(調(diào)用者死掉)這個時候你會發(fā)現(xiàn)之前正在播放的音樂也會立即停止掉。即沒有使用者服務(wù)就立馬停掉。再進一步使用方法二手動關(guān)閉“酷狗音樂”的服務(wù)。音樂也會停止,并不再啟動。這樣的設(shè)計即使遵循了上面那篇英文文章所描述的方法。就是系統(tǒng)和用戶其實在需要你服務(wù)的時候是不會把你的服務(wù)停掉的,除非系統(tǒng)和用戶真的就是要停止你,那么你這個app為啥還不讓停止的。

 

Android系統(tǒng)不會無端停止一個正在被使用的service。除非你這service自己就自己一個人硬抗,答案是你抗不住的。無論你用什么手段。除非系統(tǒng)說你是個好人放過你吧。

 

下面介紹微信為什么死不掉。先說結(jié)果。微信其實也是遵循英文文章提到的設(shè)計模式。即你有界面正在聊天的時候,服務(wù)也一直在后臺運行。一般用戶關(guān)閉微信是使用home鍵。即activity放在了后臺,即“微信”中調(diào)用者的身份還在。

但是,但是接下來的就是神奇的部分,無論使用方法一還是方法二,都阻止不了微信繼續(xù)可以收到消息。為啥呢,微信到底是使用了什么手段。什么黑科技。而且后臺確實有兩個進程,每個進程里都有一個或幾個服務(wù)。而且用方法二關(guān)閉服務(wù),很快服務(wù)又會重新出現(xiàn)。難道這個真是有兩個服務(wù)互相監(jiān)視,或者是有個非常底層的一個守護進程來保持應(yīng)用不退出。

就在此時我沒有寫代碼,而是下載了一個號稱開啟守護進程用jni開發(fā)的不死例子。

例子網(wǎng)址如下:http://download.csdn.net/detail/mihang2/9283985

下載下來并安裝到手機上,使用方法一個和二測試。方法二的時候,“正在運行的應(yīng)用程序”界面確實可以顯示停止了,即在界面里面看不到這個服務(wù)的身影,但是從調(diào)試信息里看到服務(wù)仍然還在運行者,雖然“正在運行的應(yīng)用程序”里看不到服務(wù)的身影。然后使用方法一的測試結(jié)果是,服務(wù)馬上就死掉了。那么回頭繼續(xù)來總結(jié)一下,為什么方法二沒有真正停止服務(wù)呢,我想是因為雖然activity被放置在后臺,它是它并沒有死,還在調(diào)用服務(wù)。所以服務(wù)并沒有被系統(tǒng)正真殺掉,系統(tǒng)知道調(diào)用者activity還在運行。那么為啥用方法一,服務(wù)馬上就死掉了,因為系統(tǒng)發(fā)現(xiàn)你這activity不在了,留下你這個服務(wù)也沒啥用,浪費資源和電池干脆把你立刻就停止。(當然這里只服務(wù)和調(diào)用activity在同一個進程里,即便不在一個進程里,如果沒有調(diào)用者,這個服務(wù)仍然會被殺掉)

 

那么接著回來看“微信”進程為啥可以不死。我們從另一個角度觀察微信的進程。

首先從手機正在運行的程序來看是如下結(jié)果:


從上面的截圖也可以看到這幾個進程以及對應(yīng)的服務(wù)

 

 

大家都是Android開發(fā)者,我是在windows下開發(fā)。打開命令提示符,插入一個開啟了調(diào)試模式的手機,登錄運行一個微信,輸入:“adb shell”這個時候你就進入了android手機的命令行終端,(linux終端)??梢詧?zhí)行l(wèi)inux命令。然后執(zhí)行top命令查看當前運行的進程。執(zhí)行如下命令:top –n 1 | greptencent

可以看到微信有三個進程,進程pid分別是“4087”,“4221”,“29839”

可以從ps的結(jié)果發(fā)現(xiàn),雖然是三個獨立的進程,但是他們的父進程都是396,也就是說三個進程都是由同一個進場所創(chuàng)建。

 

繼續(xù)往下看,現(xiàn)在查看我之前下載的那個關(guān)于使用的守護進程(使用jni開發(fā)的那個)例子http://download.csdn.net/detail/mihang2/9283985。

運行這個軟件,然后用top命令和ps命令看:


發(fā)現(xiàn)問題了嗎?,dameonsercice確實是有兩個進程但是者兩個進程的父進程居然不一樣,而微信的是一樣的。難道這就是其所說的守護進程。然后繼續(xù)分析,看到另一個父進程不是396的進程的父進程為9846,而這個9846,是這個dameonservice進程的pid進程。也就是說。這個守護進程是有原來的進程創(chuàng)建而來的。,因此當我使用方法一關(guān)掉activity的時候,相當于把父進程銷毀了,但是根據(jù)linux的知識,這個自進程不會被銷毀,應(yīng)該會被init進程收留成為正真linux下的守護進程,我查看了一下其它父進程為1的進程(linux守護進程)都是系統(tǒng)的軟件,沒有任何app是屬于守護進程的。應(yīng)該是Android構(gòu)架限制了吧。所以這個作者做的守護進程方法,經(jīng)過測試,其實是沒有成功的。

 

先不管這個,,先看看為啥其中一個父進程和微信的父進程一樣呢。所以來看一下,關(guān)于這個“396”進程,首先根據(jù)linux,子進程都是被父進程創(chuàng)建(fork)而來的,也就是說微信和這個應(yīng)用都有同一個父進程。使用ps | grep 396和 top –n 1 | grep396查看結(jié)果如下:

原來,所有運行的安卓app都是由zygote這個進程創(chuàng)建而來。仔細查看zygote的那一行。可以看到其pid即進程id為396。而其父進程為1,也就是說zygote是一個正真意義上的linux守護進程。又學(xué)習(xí)了一下。

 

最后這里給解釋一下微信的這么多進程到底是怎么來的,由于以上測試可知,如果用jni用c++開啟來開啟一個進程的話,那么其父進程就不會是zygote。但是現(xiàn)在我們看到的微信所有父進程都是zygote也就是說微信沒有使用jni里面創(chuàng)建進程。也就否定了其他博客對微信開啟什么守護進程的猜想了。

 

 

那么微信的這些進程到底是怎么來的呢:

我是從這篇文章看到的相關(guān)信息

http://www./a/anzhuokaifa/androidkaifa/2015/0403/2686.html

文章提到了Androidmannifest.xml里面service部分的process元素。一下是一部分的原文:

理解Android進程

你應(yīng)該已經(jīng)知道了,安卓系統(tǒng)是基于Linux的。因此,每個應(yīng)用程序都運行在其本身的進程(擁有一個獨一無二的PID)中:這允許應(yīng)用運行在一個相互隔離的環(huán)境中,不能被其他應(yīng)用程序/進程干擾。通常來說,當你想啟動一個應(yīng)用程序,Android創(chuàng)建一個進程(從Zygote中fork出來的),并 創(chuàng)建一個主線程,然后開始運行Main Activity。

你可能不知道的是,你可以指定應(yīng)用程序的一些組件運行在不同的進程中,而不是那個被用于啟動應(yīng)用程序的。先來看一下這個Nice的屬性:

android:process

該進程屬性可用于activities、services、content providers和broadcast receivers 和指定的進程中應(yīng)該執(zhí)行的特定組件。

在這個例子中,我指定MusicService必須執(zhí)行在一個單獨的“music”的進程:

<manifest ...>

  <application

    android:icon="@drawable/ic_launcher"

    android:label="@string/app_name"

    android:theme="@style/Theme.Main" >

    <activity

      android:name=".MusicActivity"

      />

    <service

      android:name=".MusicService"

      android:process=":music"

    />

  </application>

</manifest>

 

然后我們看反編譯微信里的Androidmannifest.xml,當然只反編譯了資源文件。


從內(nèi)容可以看到其中我們在之前看到的push進程是怎樣來的。

也就證明出了,微信開啟進程的方法。

 

接下來看看“微信”在面對兩種測試方法其進程到底是怎樣的。(真正的揭秘微信不死的面紗)

先從adb shell 命令里執(zhí)行top –n 1 | grep tencent來查看一下微信正常運行是的狀態(tài)。

現(xiàn)在使用方法二來停止服務(wù):

我把“正在運行”里面的可以看到的服務(wù)都關(guān)閉了,然后運行top –n 1 | grep tencent結(jié)果如下:

可見服務(wù)并沒有變化,當然按我的理解是,因為有一個后臺的activity正在使用服務(wù),所以服務(wù)沒有被系統(tǒng)銷毀了,因為我們自己的測試服務(wù)如果被方法二關(guān)閉的化,我們看到調(diào)試信息里,服務(wù)仍然在運行,也就是就像我們現(xiàn)在看到的,其實服務(wù)進程并沒有被銷毀。

然后使用方法一來停止服務(wù):

結(jié)果是,這幾條服務(wù)還在,這也就是人們感覺對微信的深不可測,沒有被銷毀。雖然,我已經(jīng)把放置到后臺的activity銷毀了,但是服務(wù)沒停。那么接下來我是怎么樣發(fā)現(xiàn)微信的不死秘密的呢。

答案如下:

我以我的魅族手機為例:可以看到加速的時候(也就是我的測試方式一)其實并沒有清除微信的任何進程,右面是華為的,華為的沒有找到具體顯示吧微信放在白名單的。但是很顯然華為系統(tǒng)是有一個“內(nèi)存加速白名單”,微信這樣的應(yīng)用就在白名單里。

再看下面?zhèn)z張圖。顯示了魅族和華為的加速白名單。微信默認就在里面。

那么按照我看到這個之后的猜想,把微信從白名單里去掉或者把我自己開發(fā)的軟件放到白名單都可以驗證“微信”殺不掉的原因。

現(xiàn)在我吧微信從白名單里移除,然后使用方法一來測試:

可以看到,微信的進程都沒有了,當然是死掉了。

知道微信為啥不死了吧,其實我查找文章的時候,看到一個論壇提到了說“系統(tǒng)給微信設(shè)置了白名單,其實微信沒有做什么黑科技”,我當時感覺不信,就此折騰了幾天。

 

 

當然,微信有好多服務(wù)和進程,只有當服務(wù)需要執(zhí)行功能的時候,我們才可以看到服務(wù)進程,也就是說微信把暫時不用的服務(wù)都停止掉了。我的測試不能排除微信使用了雙服務(wù)互相啟動,雖然微信在系統(tǒng)白名單里。

當然可以從Androidmannifest.xml看出微信使用了開機啟動,和激活屏幕啟動。當然從華為的那張截圖里可以看到微信使用wakelock,就是微信在關(guān)閉屏幕之后還在后天運行。

關(guān)于wakelock詳細內(nèi)容查看以下文章。

http://blog.sina.com.cn/s/blog_4ad7c2540101n2k2.html

其中有個選項為:PARTIAL_WAKE_LOCK:保持CPU 運轉(zhuǎn),屏幕和鍵盤燈有可能是關(guān)閉的。



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

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多