基本知识Android进程优先级1进程优先级等级一般划分方法Activte进程可见Process服务进程后台进程空进程2服务技能onStartCommand返回START_STICKYstartself服务后台onDestroy变前置,setForground(true)android:persistent=“true”3进程优先级号ProcessList.java//Adjustmentusedincertainplaceswherewedon'tknowityet.//(Generallythisissomethingthatisgoingtobecached,butwe//don'tknowtheexactvalueinthecachedrangetoassignyet.)staticfinalintUNKNOWN_ADJ=16;//Thisisaprocessonlyhostingactivitiesthatarenotvisible,//soitcanbekilledwithoutanydisruption.staticfinalintCACHED_APP_MAX_ADJ=15;staticfinalintCACHED_APP_MIN_ADJ=9;//SERVICE_ADJ列表——这些是旧的和破旧的//在Alist中不那么闪亮和有趣的服务.staticfinalintSERVICE_B_ADJ=8;//Thisistheprocessthatthepreviousapplication/Thisistheprocessthatthepreviousapplication/Thisistheprocessthatthepreviousapplication/Thisistheprocessthatthepreviousapplication其他东西,因为它很常见//切换回以前的app.Thisisimportantbothforrecent//taskswitch(togglingbetweenthetwotoprecentapps)aswellasnormal//UIflowsuchasclickingonaURIinthee-mailapptoviewinthebrowser,//andthenpressingbacktoreturntoe-mail.staticfinalintPREVIOUS_APP_ADJ=7;//Thisisaprocessholdingthehomeapplication--wewanttotry//avoidingkillingit,evenifitwouldnormallybeinthebackground,//becausetheuserinteractswithitsomuch.staticfinalintHOME_APP_ADJ=6;//Thisisaprocessholdinganapplicationservice--killingitwillnot//havemuchofanimpactasfarastheuserisconcerned.staticfinalintSERVICE_ADJ=5;//Thisisaprocesswithaheavy-weightapplication.Itisinthe//background,butwewanttotrytoavoidkillingit.Valuesetin//system/rootdir/init.rconstartup.staticfinalintHEAVY_WEIGHT_APP_ADJ=4;//Thisisaprocesscurrentlyhostingabackupoperation.Killingit//isnotentirelyfatalbutisgenerallyabadidea.staticfinalintBACKUP_APP_ADJ=3;//Thisisaprocessonlyhostingcomponentsthatareperceptibletothe//user,andwerereallywanttoavoidkillingthem,buttheyarenot//immediatelyvisible.Anexampleisbackgroundmusicplayback.staticfinalintPERCEPTIBLE_APP_ADJ=2;//Thisisaprocessonlyhostingactivitiesthatarevisibletothe//user,sowe'dprefertheydon'tdisappear.staticfinalintVISIBLE_APP_ADJ=1;//Thisistheprocessrunningthecurrentforegroundapp.We'dreally//rathernotkillit!staticfinalintFOREGROUND_APP_ADJ=0;//Thisisaprocessthatthesystemorapersistentprocesshasboundto,//andindicateditisimportant.staticfinalintPERSISTENT_SERVICE_ADJ=-11;//Thisisasystempersistentprocess,suchastelephony.Definitely//don'twanttokillit,butdoingsoisnotcompletelyfatal.staticfinalintPERSISTENT_PROC_ADJ=-12;//Thesystemprocessrunsatthedefaultadjustment.staticfinalintSYSTEM_ADJ=-16;//Specialcodefornativeprocessesthatarenotbeingmanagedbythesystem(so//don'thaveanoomadjassignedbythesystem).staticfinalintNATIVE_ADJ=-17;AndroidLowMemoryKiller当Android系统内存不足时,系统会杀掉一些进程来释放空间。谁生谁死的生死权由LMK决定。这是Android系统中的LowMemoryKiller,它是基于Linux的。OOM机制,其阈值定义为lo在wmemorykiller文件中,当然也可以通过系统的init.rc.cstaticuint32_tlowmem_debug_level=1;staticintlowmem_adj[6]={0,1,6,12,};staticintlowmem_adj_size=4;staticintlowmem_minfree[6]实现一个自定义的lowmemorykiller={3*512,/*6MB*/2*1024,/*8MB*/4*1024,/*16MB*/16*1024,/*64MB*/};staticintlowmem_minfree_size=4;①通过LowMemoryKiller中进程的oom_adj占用内存的大小决定了要杀掉的进程,oom_adj的值越小越不容易被杀掉。其中lowmem_minfree是杀掉进程的时间。谁被杀死取决于lowmem_adj。具体含义参考上面的Android进程优先级。②init进程(系统进程)的oom_adj在init.rc中定义为-16,不可能被杀死(init的PID为1),前台进程为0(这里的前台进程指的是用户正在使用的Activity所在的进程),用户按下Home键返回桌面时的优先级为6,正常的Service进程为8.init.rc#Setinitanditsforkedchildren'soom_adj.write/proc/1/oom_adj-16LowMemoryKiller的具体实现原理请参考Ref-2。查看一个App的流程步骤(手机和PC连接)adbshellps|grepprocessnamecat/proc/pid/oom_adj//其中pid为上面grepLinuxAM命令获取的进程号am命令:启动一个Activity,Service,在Android系统中通过adbshell进行调用,启动浏览器和其他命令来操作Android。它的源代码在Am.java中。在shell环境下执行am命令其实是启动了一个线程去执行Am.java中的main函数(main方法),am命令后面的参数会作为Runtime参数传递给main函数,主要是实现在Am.java的run方法中。调用命令:amstart-aandroid.intent.action.CALL-dtel:电话号码示例:amstart-aandroid.intent.action.CALL-dtel:10086打开网页命令:amstart-aandroid.intent.action.VIEW-dURL示例:amstart-aandroid.intent.action.VIEW-dhttp://www.skyseraph.com启动服务命令:amstartservice<服务名称>示例:amstartservice-ncom.android.music/com.android.music.MediaPlaybackServiceNotificationListenerService“当发布或删除新通知,或者它们的排名发生变化时,从系统接收调用的服务。”来自Google是用来监听通知的发送和移除以及排名位置的变化,如果我们注册了这个服务,当任何系统通知到达或者被移除的时候,我们可以通过这个服务来监听,甚至可以做一些管理工作。Android账号和同步机制属于Android中比较冷门的知识。详见Ref3/4/5Android多进程实现:android:process好处:独立进程可以充分利用自己的RAM预算,让主进程有更多的空间处理资源。此外,操作系统以不同方式对待运行在不同组件中的进程。这意味着当系统在低内存条件下运行时,并非所有进程都会被杀死:每个进程都会有自己的DalvikVM实例,这意味着您不能在这些实例之间共享数据,至少不能在传统意义上共享数据。例如,静态字段在每个进程中都有自己的值,而不是您倾向于认为的只有一个值。详情请参考Ref9ExistingMethodNetworkConnectionKeepAliveMethodA.GCMB。公共第三方推送通道(信鸽等)C.与服务器自轮询,或长连接。具体实现可以参考微信架构师杨倩蓉《微信安卓客户端后台保活经验分享》(Ref-1)。双服务(通知栏)提高进程优先级思路:(API级别>18)应用启动时启动一个假服务(FakeService),startForeground(),传递一个空的Notification启动真正的服务(AlwaysLiveService),startForeground(),注意同一个NotificationIDFakeServicestopForeground()作用:通过adb查看,后台运行的服务进程号变为1(优先级仅次于前台进程)风险:前台服务存在漏洞Android系统,6.0以上系统可修复实现:核心代码如下(newIntent(this,FakeService.class));returnsuper.onStartCommand(intent,flags,startId);}FakeService临时服务publicclassFakeServiceextendsService{@Nullable@OverridepublicIBinderonBind(Intentintent){returnull;}@OverridepublicintonStartCommand(Intentintent,intflags,intstartId){startForeground(R.id.notify,newNotification());stopSelf();returnsuper.onStartCommand(intent,flags,startId);}@OverridepublicvoidonDestroy(){stopForeground(true);super.onDestroy();}}服务通过监听及时拉起AlarmReceiver、ConnectReceiver、BootReceiver等服务设置(见上面基础部分)系统广播,如开机、锁屏、亮屏等重启服务通过闹钟定时器,启动服务守护进程/进程互拉在分析360手机助手app时发现,它有N个多个进程,一个进程会被其他未确定的进程杀死kill的进程被拉起,这也是一种思路,虽然有点流氓~daemon进程一般有两种方式:多个java进程互相守卫拉底层C守护进程拉起App上层/java进程LinuxAm命令启动后台进程底层防止进程被kill的方法。Android4.4及以上版本可能存在兼容性问题。详见Ref-7NotificationListenerServiceNotification,一种需要用户允许特定权限的系统上拉方法。4.3以上系统前台悬浮窗有朋友提出在应用退出后启动非交互悬浮窗。我个人认为这种方法是无效的。有兴趣的读者可以试试新的方法(AccountSync),利用Android系统提供的账户和同步机制,通过adb实现效果,后台运行的服务的进程号变为1(优先级仅次于前台进程),可以提高进程优先级。与下图正常情况相比,通过AccountSyncAdapter方法杀死进程后,进程被系统杀死后,synSyncAdapter的时间进度不高,往往是因为手机处于休眠状态,后期调整时间,最小同步间隔为1分钟,用户可自行停止或删除,部分手机账号默认不同步,需要手动开启(核心代码)1.建立一个数据同步系统(ContentProvider),通过一个ContentProvider进行数据同步。由于没有实际的数据同步,这里可以直接创建一个空的ContentProvider。publicclassXXAccountProviderextendsContentProvider{publicstaticfinalStringAUTHORITY="包名.provider";publicstaticfinalStringCONTENT_URI_BASE="content://"+AUTHORITY;publicstaticfinalStringTABLE_NAME="data";publicstaticfinalUriCONTENT_URI=Uri.parse(CONTENT_URI_BASE+"/"+TABLE_NAME);@OverridepublicbooleanonCreate(){returntrue;}@Nullable@OverridepublicCursorquery(Uriuri,String[]projection,Stringselection,String[]selectionArgs,StringsortOrder){returnnull;}@Nullable@OverridepublicStringgetType(Uriuri){returnnewString();}@Nullable@OverridepublicUriinsert(Uriuri,ContentValuesvalues){returnnull;}@Overridepublicintdelete(Uriuri,Stringselection,String[]selectionArgs){return0;}@Overridepublicintupdate(Uriuri,ContentValuesvalues,Stringselection,String[]selectionArgs){return0;}}然后再Manifest中声明
