首页 > 网站 > 建站经验 > 正文

Android下写一个永远不会!被KILL掉的进程/服务

2019-11-02 14:33:26
字体:
来源:转载
供稿:网友

  Android 系统对于内存管理有自己的一套方法,为了保障系统有序稳定的运信,系统内部会自动分配,控制程序的内存使用。当系统觉得当前的资源非常有限的时候,为了保证一些优先级高的程序能运行,就会杀掉一些他认为不重要的程序或者服务来释放内存。这样就能保证真正对用户有用的程序仍然再运行。如果你的 Service 碰上了这种情况,多半会先被杀掉。但如果你增加 Service 的优先级就能让他多留一会,我们可以用 setForeground(true) 来设置 Service 的优先级。

 为什么是 foreground ? 默认启动的 Service 是被标记为 background,当前运行的 Activity 一般被标记为 foreground,也就是说你给 Service 设置了 foreground 那么他就和正在运行的 Activity 类似优先级得到了一定的提高。当让这并不能保证你得 Service 永远不被杀掉,只是提高了他的优先级。 有一个方法可以给你更清晰的演示,进入 $SDK/tools 运行命令 复制代码# adb shell dumpsys activity|grep oom_adj      Running Norm Proc # 6: oom_adj=  0 ProcessRecord{43635cf0 12689:com.roiding.netraffic/10028}   Running Norm Proc # 5: oom_adj=  7 ProcessRecord{436feda0 12729:com.android.browser/10006}   Running Norm Proc # 4: oom_adj=  8 ProcessRecord{4367e838 12761:android.process.acore/10016}   Running Norm Proc # 3: oom_adj=  8 ProcessRecord{43691cd8 12754:com.google.process.gapps/10000}   Running PERS Proc # 1: oom_adj=-12 ProcessRecord{43506750 5941:com.android.phone/1001}   Running PERS Proc # 0: oom_adj=-100 ProcessRecord{4348fde0 5908:system/1000}复制代码返回的一大堆东西,观察 oom_adj 的值,如果是大于 8 一般就是属于 backgroud 随时可能被干掉,数值越小证明优先级越高,被干掉的时间越晚。你看phone的程序是 -12 说明电话就是电话,其他什么都干了了,也的能接电话对吧。另外还有一个 -100 的,更邪乎因为是 system 如果他也完蛋了,你得系统也就挂了。 我是天王盖地虎的分割线          
琪琪影院[www.aikan.tv/special/qiqiyingyuan/]
                       从Android 1.5开始,一个已启动的service可以调用startForeground(int, Notification)将service置为foreground状态,调用stopForeground(boolean)将service置为 background状态。 我们会在调用startForeground(int, Notification)传入参数notification,它会在状态栏里显示正在进行的foreground service。background service不会在状态栏里显示。  在Android 1.0中,将一个service置为foreground状态: setForeground(true); mNM.notify(id, notification);将一个service置为background状态: mNM.cancel(id); setForeground(false);对比看出,在1.0 API中调用setForeground(boolean)只是简单的改变service的状态,用户不会有任何觉察。新API中强制将 notification和改变service状态的动作绑定起来,foreground service会在状态栏显示,而background service不会。 我是天王盖地虎的分割线                                  通过在androidmanifest.xml中的application标签中加入android:persistent="true"属性后的确就能够达到保证该应用程序所在进程不会被LMK杀死。但有个前提就是应用程序必须是系统应用,也就是说应用程序不能采用通常的安装方式。必须将应用程序的apk包直接放到/system/app目录下。而且必须重启系统后才能生效。 除了一般的几种优先级外,还存在着coreserver,system这样的永远不会被LMK回收的优先级。系统中的电话应用就是coreserver优先级的。 通过查看源代码可以知道,只有应用程序的flag同时为FLAG_SYSTEM和FLAG_PERSISTENT时,才会被设置为coreserver优先级 if ((info.flags&(ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT))                == (ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT)) {            app.persistent = true;            app.maxAdj = CORE_SERVER_ADJ;        }FLAG_SYSTEM在应用程序apk放在/system/app下时会被设置。所以才会出现只设置android:persistent="true"仍然会被杀死的情况。 测试时发现,将应用程序放到/system/app后不重启系统,仍然会被识别为普通的进程。当系统重新启动时,会在一开始就启动该进程并把它优先级设置为coreserver。 通过dumpsys activity命令能够很明显的看出其中差别。 复制代码Running processes (most recent first):    App  # 3: adj=   2/1 ProcessRecord{30858c20 1877:com.android.email/10014} (started-services)    PERS # 2: adj=-100/0 ProcessRecord{308fb390 1713:system/1000} (fixed)    App  # 1: adj=   0/0 ProcessRecord{30908198 1794:android.process.acore/10005} (top-activity)    PERS # 0: adj= -12/0 ProcessRecord{3090d488 1789:xiao.xiong.test/10026} (fixed)复制代码而且adj=-12时,这个进程通过ddms手动stop后会立即启动 我是天王盖地虎的分割线                                  方法对于一个service,可以首先把它设为在前台运行: 复制代码public void MyService.onCreate() {        super.onCreate();        Notification notification = new Notification(android.R.drawable.my_service_icon,"my_service_name",System.currentTimeMillis());        PendingIntent p_intent = PendingIntent.getActivity(this, 0,                new Intent(this, MyMainActivity.class), 0);        notification.setLatestEventInfo(this, "MyServiceNotification, "MyServiceNotification is Running!",p_intent);        Log.d(TAG, String.format("notification = %s", notification));        startForeground(0x1982, notification);   // notification ID: 0x1982, you can name it as you will.}复制代码相较于/data/app下的应用,放在/system/app下的应用享受更多的特权,比如若在其Manifest.xml文件中设置persistent属性为true,则可使其免受out-of-memory killer的影响。 如应用程序'Phone'的AndroidManifest.xml文件: <application android:name="PhoneApp"                 android:persistent="true"                 android:label="@string/dialerIconLabel"                 android:icon="@drawable/ic_launcher_phone">         ...    </application>设置后app提升为系统核心级别,任何情况下不会被kill掉, settings->applications里面也会屏蔽掉stop操作。 复制代码这样设置前的log:   Proc #19: adj=svc  /B 4067b028 255:com.xxx.xxx/10001 (started-services)    # cat /proc/255/oom_adj    4设置后的log:  PERS #19: adj=core /F 406291f0 155:com.xxx.xxx/10001 (fixed)    # cat /proc/155/oom_adj     -12                # 这是CORE_SERVER_ADJ注:init进程的oom_adj为-16(即SYSTEM_ADJ): cat  /proc/1/oom_adj复制代码Android相关部分分析在文件frameworks/base/services/java/com/android/server/am/ActivityManagerService.java中有以下的代码: 复制代码final ProcessRecord addAppLocked(ApplicationInfo info) {        ProcessRecord app = getProcessRecordLocked(info.processName, info.uid);         if (app == null) {            app = newProcessRecordLocked(null, info, null);            mProcessNames.put(info.processName, info.uid, app);            updateLruProcessLocked(app, true, true);        }             if ((info.flags&(ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT))                == (ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT)) {            app.persistent = true;            app.maxAdj = CORE_SERVER_ADJ;             // 这个常数值为-12。        }            if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) {            mPersistentStartingProcesses.add(app);            startProcessLocked(app, "added application", app.processName);        }             return app;    }复制代码可见要想成为core service (即app.maxAdj = CORE_SERVER_ADJ(-12)),应用程序需要FLAG_SYSTEM和FLAG_PERSISTENT两个标志,FLAG_SYSTEM指的是应用位于/system/app下,FLAG_PERSISTENT就是指persistent属性。 而对于frameworks/base/services/java/com/android/server/SystemServer.java,则调用ActivityManagerService.setSystemProcess(); 把自己的 app.maxAdj 设置成SYSTEM_ADJ,即-16。 我是天王盖地虎的分割线                                  Android中的进程是托管的,当
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表