精华内容
下载资源
问答
  • Android 服务保活

    千次阅读 2019-01-22 10:46:54
    自己曾经也在这个问题上伤过脑经...结合很多资料,今天总结一下Android进程保活的一些方案,都附有完整的实现源码,有些可能你已经知道,但是有些你可能是第一次听说,(1像素Activity,前台服务,账号同步,Jobsc...

     

    自己曾经也在这个问题上伤过脑经,前几日刚好有一个北京的哥们在QQ说在做IM类的项目,问我进程保活如何处理比较恰当,决定去总结一下,网上搜索一下进程常驻的方案好多好多,但是很多的方案都是不靠谱的或者不是最好的,结合很多资料,今天总结一下Android进程保活的一些方案,都附有完整的实现源码,有些可能你已经知道,但是有些你可能是第一次听说,(1像素Activity,前台服务,账号同步,Jobscheduler,相互唤醒,系统服务捆绑,如果你都了解了,请忽略)经过多方面的验证,Android系统中在没有白名单的情况下做一个任何情况下都不被杀死的应用是基本不可能的,但是我们可以做到我们的应用基本不被杀死,如果杀死可以马上满血复活,原谅我讲的特别含蓄,毕竟现在的技术防不胜防啊,不死应用还是可能的。

    有几个问题需要思考,系统为什么会杀掉进程,杀的为什么是我的进程,这是按照什么标准来选择的,是一次性干掉多个进程,还是一个接着一个杀,保活套路一堆,如何进行进程保活才是比较恰当......如果这些问题你还还存在,或许这篇文章可以解答。

    一、进程初步了解

    每一个Android应用启动后至少对应一个进程,有的是多个进程,而且主流应用中多个进程的应用比例较大

    Paste_Image.png

    1、如何查看进程解基本信息

    对于任何一个进程,我们都可以通过adb shell ps|grep <package_name>的方式来查看它的基本信息

    解释
    u0_a16 USER 进程当前用户
    3881 进程ID
    1223 进程的父进程ID
    873024 进程的虚拟内存大小
    37108 实际驻留”在内存中”的内存大小
    com.wangjing.processlive 进程名

    2、进程划分

    Android中的进程跟封建社会一样,分了三流九等,Android系统把进程的划为了如下几种(重要性从高到低),网上多位大神都详细总结过(备注:严格来说是划分了6种)。

    2.1、前台进程(Foreground process)

    场景:

    • 某个进程持有一个正在与用户交互的Activity并且该Activity正处于resume的状态。
    • 某个进程持有一个Service,并且该Service与用户正在交互的Activity绑定。
    • 某个进程持有一个Service,并且该Service调用startForeground()方法使之位于前台运行。
    • 某个进程持有一个Service,并且该Service正在执行它的某个生命周期回调方法,比如onCreate()、 onStart()或onDestroy()。
    • 某个进程持有一个BroadcastReceiver,并且该BroadcastReceiver正在执行其onReceive()方法。

    用户正在使用的程序,一般系统是不会杀死前台进程的,除非用户强制停止应用或者系统内存不足等极端情况会杀死。

    2.2、可见进程(Visible process)

    场景:

    • 拥有不在前台、但仍对用户可见的 Activity(已调用 onPause())。
    • 拥有绑定到可见(或前台)Activity 的 Service

    用户正在使用,看得到,但是摸不着,没有覆盖到整个屏幕,只有屏幕的一部分可见进程不包含任何前台组件,一般系统也是不会杀死可见进程的,除非要在资源吃紧的情况下,要保持某个或多个前台进程存活

    2.3、服务进程(Service process)

    场景

    • 某个进程中运行着一个Service且该Service是通过startService()启动的,与用户看见的界面没有直接关联。

    在内存不足以维持所有前台进程和可见进程同时运行的情况下,服务进程会被杀死

    2.4、后台进程(Background process)

    场景:

    • 在用户按了"back"或者"home"后,程序本身看不到了,但是其实还在运行的程序,比如Activity调用了onPause方法

    系统可能随时终止它们,回收内存

    2.5、空进程(Empty process)

    场景:

    • 某个进程不包含任何活跃的组件时该进程就会被置为空进程,完全没用,杀了它只有好处没坏处,第一个干它!

    3、内存阈值

    上面是进程的分类,进程是怎么被杀的呢?系统出于体验和性能上的考虑,app在退到后台时系统并不会真正的kill掉这个进程,而是将其缓存起来。打开的应用越多,后台缓存的进程也越多。在系统内存不足的情况下,系统开始依据自身的一套进程回收机制来判断要kill掉哪些进程,以腾出内存来供给需要的app, 这套杀进程回收内存的机制就叫 Low Memory Killer。那这个不足怎么来规定呢,那就是内存阈值,我们可以使用cat /sys/module/lowmemorykiller/parameters/minfree来查看某个手机的内存阈值。


    注意这些数字的单位是page. 1 page = 4 kb.上面的六个数字对应的就是(MB): 72,90,108,126,144,180,这些数字也就是对应的内存阀值,内存阈值在不同的手机上不一样,一旦低于该值,Android便开始按顺序关闭进程. 因此Android开始结束优先级最低的空进程,即当可用内存小于180MB(46080*4/1024)。

     

    读到这里,你或许有一个疑问,假设现在内存不足,空进程都被杀光了,现在要杀后台进程,但是手机中后台进程很多,难道要一次性全部都清理掉?当然不是的,进程是有它的优先级的,这个优先级通过进程的adj值来反映,它是linux内核分配给每个系统进程的一个值,代表进程的优先级,进程回收机制就是根据这个优先级来决定是否进行回收,adj值定义在com.android.server.am.ProcessList类中,这个类路径是${android-sdk-path}\sources\android-23\com\android\server\am\ProcessList.java。oom_adj的值越小,进程的优先级越高,普通进程oom_adj值是大于等于0的,而系统进程oom_adj的值是小于0的,我们可以通过cat /proc/进程id/oom_adj可以看到当前进程的adj值。

     

     

    看到adj值是0,0就代表这个进程是属于前台进程,我们按下Back键,将应用至于后台,再次查看

     


    adj值变成了8,8代表这个进程是属于不活跃的进程,你可以尝试其他情况下,oom_adj值是多少,但是每个手机的厂商可能不一样,oom_adj值主要有这么几个,可以参考一下。

    adj级别 解释
    UNKNOWN_ADJ 16 预留的最低级别,一般对于缓存的进程才有可能设置成这个级别
    CACHED_APP_MAX_ADJ 15 缓存进程,空进程,在内存不足的情况下就会优先被kill
    CACHED_APP_MIN_ADJ 9 缓存进程,也就是空进程
    SERVICE_B_ADJ 8 不活跃的进程
    PREVIOUS_APP_ADJ 7 切换进程
    HOME_APP_ADJ 6 与Home交互的进程
    SERVICE_ADJ 5 有Service的进程
    HEAVY_WEIGHT_APP_ADJ 4 高权重进程
    BACKUP_APP_ADJ 3 正在备份的进程
    PERCEPTIBLE_APP_ADJ 2 可感知的进程,比如那种播放音乐
    VISIBLE_APP_ADJ 1 可见进程
    FOREGROUND_APP_ADJ 0 前台进程
    PERSISTENT_SERVICE_ADJ -11 重要进程
    PERSISTENT_PROC_ADJ -12 核心进程
    SYSTEM_ADJ -16 系统进程
    NATIVE_ADJ -17 系统起的Native进程

    备注:(上表的数字可能在不同系统会有一定的出入)

    根据上面的adj值,其实系统在进程回收跟内存回收类似也是有一套严格的策略,可以自己去了解,大概是这个样子的,oom_adj越大,占用物理内存越多会被最先kill掉,OK,那么现在对于进程如何保活这个问题就转化成,如何降低oom_adj的值,以及如何使得我们应用占的内存最少。

    一、进程保活方案

    1、开启一个像素的Activity

    据说这个是手Q的进程保活方案,基本思想,系统一般是不会杀死前台进程的。所以要使得进程常驻,我们只需要在锁屏的时候在本进程开启一个Activity,为了欺骗用户,让这个Activity的大小是1像素,并且透明无切换动画,在开屏幕的时候,把这个Activity关闭掉,所以这个就需要监听系统锁屏广播,我试过了,的确好使,如下。

    public class MainActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
       }
    }
    

    如果直接启动一个Activity,当我们按下back键返回桌面的时候,oom_adj的值是8,上面已经提到过,这个进程在资源不够的情况下是容易被回收的。现在造一个一个像素的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();
            //宽高设计为1个像素
            attributes.width = 1;
            attributes.height = 1;
            //起始坐标
            attributes.x = 0;
            attributes.y = 0;
            window.setAttributes(attributes);
    
            ScreenManager.getInstance(this).setActivity(this);
        }
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            Log.d(TAG, "onDestroy");
        }
    }
    
    
    

    为了做的更隐藏,最好设置一下这个Activity的主题,当然也无所谓了

       <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>
    

    在屏幕关闭的时候把LiveActivity启动起来,在开屏的时候把LiveActivity 关闭掉,所以要监听系统锁屏广播,以接口的形式通知MainActivity启动或者关闭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状态广播接收者
         */
        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() {
            //结束掉LiveActivity
            if (mActivityWref != null) {
                Activity activity = mActivityWref.get();
                if (activity != null) {
                    activity.finish();
                }
            }
        }
    }
    

    现在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之后,进行锁屏,现在测试一下oom_adj的值

     

    果然将进程的优先级提高了。

    但是还有一个问题,内存也是一个考虑的因素,内存越多会被最先kill掉,所以把上面的业务逻辑放到Service中,而Service是在另外一个 进程中,在MainActivity开启这个服务就行了,这样这个进程就更加的轻量,

    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) {
            //屏幕关闭的时候启动一个1像素的Activity,开屏的时候关闭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,通过上面的操作,我们的应用就始终和前台进程是一样的优先级了,为了省电,系统检测到锁屏事件后一段时间内会杀死后台进程,如果采取这种方案,就可以避免了这个问题。但是还是有被杀掉的可能,所以我们还需要做双进程守护,关于双进程守护,比较适合的就是aidl的那种方式,但是这个不是完全的靠谱,原理是A进程死的时候,B还在活着,B可以将A进程拉起来,反之,B进程死的时候,A还活着,A可以将B拉起来。所以双进程守护的前提是,系统杀进程只能一个个的去杀,如果一次性杀两个,这种方法也是不OK的。

    事实上
    那么我们先来看看Android5.0以下的源码,ActivityManagerService是如何关闭在应用退出后清理内存的

    Process.killProcessQuiet(pid);  
    

    应用退出后,ActivityManagerService就把主进程给杀死了,但是,在Android5.0以后,ActivityManagerService却是这样处理的:

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

    在应用退出后,ActivityManagerService不仅把主进程给杀死,另外把主进程所属的进程组一并杀死,这样一来,由于子进程和主进程在同一进程组,子进程在做的事情,也就停止了。所以在Android5.0以后的手机应用在进程被杀死后,要采用其他方案。

    2、前台服务

    这种大部分人都了解,据说这个微信也用过的进程保活方案,移步微信Android客户端后台保活经验分享,这方案实际利用了Android前台service的漏洞。
    原理如下
    对于 API level < 18 :调用startForeground(ID, new Notification()),发送空的Notification ,图标则不会显示。
    对于 API level >= 18:在需要提优先级的service A启动一个InnerService,两个服务同时startForeground,且绑定同样的 ID。Stop 掉InnerService ,这样通知栏图标即被移除。

    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以下,直接发送Notification并将其置为前台
            if (Build.VERSION.SDK_INT <Build.VERSION_CODES.JELLY_BEAN_MR2) {
                startForeground(NOTIFICATION_ID, new Notification());
            } else {
                //API 18以上,发送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();
                //发送与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);
            
            }
        }
    }
    

    在没有采取前台服务之前,启动应用,oom_adj值是0,按下返回键之后,变成9(不同ROM可能不一样)

    在采取前台服务之后,启动应用,oom_adj值是0,按下返回键之后,变成2(不同ROM可能不一样),确实进程的优先级有所提高。

     

    3、相互唤醒

    相互唤醒的意思就是,假如你手机里装了支付宝、淘宝、天猫、UC等阿里系的app,那么你打开任意一个阿里系的app后,有可能就顺便把其他阿里系的app给唤醒了。这个完全有可能的。此外,开机,网络切换、拍照、拍视频时候,利用系统产生的广播也能唤醒app,不过Android N已经将这三种广播取消了。

    LBE安全大师

     

    LBE安全大师

    如果应用想保活,要是QQ,微信愿意救你也行,有多少手机上没有QQ,微信呢?或者像友盟,信鸽这种推送SDK,也存在唤醒app的功能。
    拉活方法

    4、JobSheduler

    JobSheduler是作为进程死后复活的一种手段,native进程方式最大缺点是费电, Native 进程费电的原因是感知主进程是否存活有两种实现方式,在 Native 进程中通过死循环或定时器,轮训判断主进程是否存活,当主进程不存活时进行拉活。其次5.0以上系统不支持。 但是JobSheduler可以替代在Android5.0以上native进程方式,这种方式即使用户强制关闭,也能被拉起来,亲测可行。

      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、粘性服务&与系统服务捆绑

    这个是系统自带的,onStartCommand方法必须具有一个整形的返回值,这个整形的返回值用来告诉系统在服务启动完毕后,如果被Kill,系统将如何操作,这种方案虽然可以,但是在某些情况or某些定制ROM上可能失效,我认为可以多做一种保保守方案

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        return START_REDELIVER_INTENT;
    }
    
    • START_STICKY
      如果系统在onStartCommand返回后被销毁,系统将会重新创建服务并依次调用onCreate和onStartCommand(注意:根据测试Android2.3.3以下版本只会调用onCreate根本不会调用onStartCommand,Android4.0可以办到),这种相当于服务又重新启动恢复到之前的状态了)。

    • START_NOT_STICKY
      如果系统在onStartCommand返回后被销毁,如果返回该值,则在执行完onStartCommand方法后如果Service被杀掉系统将不会重启该服务。

    • START_REDELIVER_INTENT
      START_STICKY的兼容版本,不同的是其不保证服务被杀后一定能重启。

    相比与粘性服务与系统服务捆绑更厉害一点,这个来自爱哥的研究,这里说的系统服务很好理解,比如NotificationListenerService,NotificationListenerService就是一个监听通知的服务,只要手机收到了通知,NotificationListenerService都能监听到,即时用户把进程杀死,也能重启,所以说要是把这个服务放到我们的进程之中,那么就可以呵呵了

    @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) {
        }
    }
    

    但是这种方式需要权限

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

    所以你的应用要是有消息推送的话,那么可以用这种方式去欺骗用户。

    结束:
    听说账号同步唤醒APP这种机制很不错,用户强制停止都杀不起创建一个账号并设置同步器,创建周期同步,系统会自动调用同步器,这样就能激活我们的APP,局限是国产机会修改最短同步周期(魅蓝NOTE2长达30分钟),并且需要联网才能使用。在国内各大ROM"欣欣向荣"的大背景下,关于进程保活,不加入白名单,我也很想知道有没有一个应用永活的方案,这种方案性能好,不费电,或许做不到,或许有牛人可以,但是,通过上面几种措施,在绝大部分的机型下,绝大部分用户手机中,我们的进程寿命确实得到了提高,这篇文章都是围绕怎么去提高进程oom_adj的值来进行,关于降低内存占用方面,移步
    Android性能优化的方方面面,所以关于我们的应用更加“健康”,性能优化必不可少。

    DEMO地址:https://github.com/herojing/KeepProcessLive

     

    写在前头
    保活Service我们需要做什么:

    1.在应用被关闭后保活(最难)

    2.在内用占用过大,系统自动释放内存时保活(优先杀死占用较高的Service)

    3.重启手机后自动开启Service

    4.手机息屏后不被释放内存

    5.手动清理内存时保活

     

    首先介绍一下Service的等级:

    一、前台进程
    二、可见进程
    三、服务进程
    四、后台进程
    五、空进程  ---关闭应用后,没有清理缓存

    所以为了提高优先级我们可以使用startForeground()方法将Service设置为前台进程。

     

    一、在AndroidManifest中添加Service

    <service android:name=".modle.StepService"
                android:process="istep.service"  //放入新进程
                >
                <intent-filter android:priority="1000">
                    <!-- 系统启动完成后会调用-->
                    <action android:name="android.intent.action.BOOT_COMPLETED"/>
                    <action android:name="android.intent.action.DATE_CHANGED"/>
                    <action android:name="android.intent.action.MEDIA_MOUNTED" />
                    <action android:name="android.intent.action.USER_PRESENT" />
                    <action android:name="android.intent.action.ACTION_TIME_TICK" />
                    <action android:name="android.intent.action.ACTION_POWER_CONNECTED" />
                    <action android:name="android.intent.action.ACTION_POWER_DISCONNECTED" />
                </intent-filter>
    </service>
     
     
    <service android:name=".modle.GuardService"
                android:process=":GuardService">
                <intent-filter >
                    <!-- 系统启动完成后会调用-->
                    <action android:name="android.intent.action.BOOT_COMPLETED"/>
                    <action android:name="android.intent.action.DATE_CHANGED"/>
                    <action android:name="android.intent.action.MEDIA_MOUNTED" />
                    <action android:name="android.intent.action.USER_PRESENT" />
                    <action android:name="android.intent.action.ACTION_TIME_TICK" />
                    <action android:name="android.intent.action.ACTION_POWER_CONNECTED" />
                    <action android:name="android.intent.action.ACTION_POWER_DISCONNECTED" />
                </intent-filter>
            </service>


     

    二、双进程保护
    1.创建aidl实现跨进程通信(新建一个aidl)
     

    
    interface ProcessConnection {
        /**
         * Demonstrates some basic types that you can use as parameters
         * and return values in AIDL.
         */
        //删除不必要方法
     }

    2.创建主服务

    /**
     * 主进程 双进程通讯
     * Created by db on 2018/1/11.
     */
     
    public class StepService extends Service{
        @Nullable
        @Override
        public IBinder onBind(Intent intent) {
            return new ProcessConnection.Stub() {};
        }
     
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            startForeground(1,new Notification());
            //绑定建立链接
            bindService(new Intent(this,GuardService.class),
                    mServiceConnection, Context.BIND_IMPORTANT);
            return START_STICKY;
        }
     
        private ServiceConnection mServiceConnection = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
                //链接上
                Log.d("test","StepService:建立链接");
            }
     
            @Override
            public void onServiceDisconnected(ComponentName componentName) {
                //断开链接
                startService(new Intent(StepService.this,GuardService.class));
                //重新绑定
                bindService(new Intent(StepService.this,GuardService.class),
                        mServiceConnection, Context.BIND_IMPORTANT);
            }
        };
     
    }


     

    3.创建守护服务

     /**
     * 守护进程 双进程通讯
     * Created by db on 2018/1/11.
     */
     
    public class GuardService extends Service{
        @Nullable
        @Override
        public IBinder onBind(Intent intent) {
            return new ProcessConnection.Stub() {};
        }
     
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            startForeground(1,new Notification());
            //绑定建立链接
            bindService(new Intent(this,StepService.class),
                    mServiceConnection, Context.BIND_IMPORTANT);
            return START_STICKY;
        }
     
        private ServiceConnection mServiceConnection = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
                //链接上
                Log.d("test","GuardService:建立链接");
            }
     
            @Override
            public void onServiceDisconnected(ComponentName componentName) {
                //断开链接
                startService(new Intent(GuardService.this,StepService.class));
                //重新绑定
                bindService(new Intent(GuardService.this,StepService.class),
                        mServiceConnection, Context.BIND_IMPORTANT);
            }
        };
     
    }


     
     

    返回参数含义:

     

    START_STICKY:在Service被关闭后,重新开启Service
    START_NOT_STICKY:服务被异常杀掉后,系统将会被设置为started状态,系统不会重启该服务,直到startService(Intent intent)方法再次被调用。
    START_REDELIVER_INTENT:重传Intent,使用这个返回值时,如果在执行完onStartCommand后,服务被异常kill掉,系统会自动重启该服务,并将Intent的值传入。
    START_STICKY_COMPATIBILITY:START_STICKY的兼容版本,但不保证服务被kill后一定能重启。
     

    三、使用JobService来实现应用退出后重启Service
     

    1、在AndroidManifest中添加Service和权限

    <!--JobService权限-->
        <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
    <receiver android:name=".modle.BootCompleteReceiver">
                <intent-filter>
                    <action android:name="android.intent.action.BOOT_COMPLETED"/>
                </intent-filter>
    </receiver>


    2、JobService代码

    /**
     * 用于判断Service是否被杀死
     * Created by db on 2018/1/11.
     */
    @TargetApi(Build.VERSION_CODES.LOLLIPOP)//5.0以后可用
    public class JobWakeUpService extends JobService{
        private int JobWakeUpId = 1;
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            //开启轮寻
            JobInfo.Builder mJobBulider = new JobInfo.Builder(
                    JobWakeUpId,new ComponentName(this,JobWakeUpService.class));
            //设置轮寻时间
            mJobBulider.setPeriodic(2000);
            JobScheduler mJobScheduler = (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE);
            mJobScheduler.schedule(mJobBulider.build());
            return START_STICKY;
        }
     
        @Override
        public boolean onStartJob(JobParameters jobParameters) {
            //开启定时任务 定时轮寻 判断应用Service是否被杀死
            //如果被杀死则重启Service
            boolean messageServiceAlive = serviceAlive(StepService.class.getName());
            if(!messageServiceAlive){
                startService(new Intent(this,StepService.class));
            }
     
            return false;
        }
     
        @Override
        public boolean onStopJob(JobParameters jobParameters) {
     
            return false;
        }
     
        /**
         * 判断某个服务是否正在运行的方法
         * @param serviceName
         *            是包名+服务的类名(例如:net.loonggg.testbackstage.TestService)
         * @return true代表正在运行,false代表服务没有正在运行
         */
        private boolean serviceAlive(String serviceName) {
            boolean isWork = false;
            ActivityManager myAM = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE);
            List<ActivityManager.RunningServiceInfo> myList = myAM.getRunningServices(100);
            if (myList.size() <= 0) {
                return false;
            }
            for (int i = 0; i < myList.size(); i++) {
                String mName = myList.get(i).service.getClassName().toString();
                if (mName.equals(serviceName)) {
                    isWork = true;
                    break;
                }
            }
            return isWork;
        }
    }
    

    四、保证Service在开机后自动启动

    (1)注册广播
    
      <receiver android:name=".modle.mReceiver">
                <intent-filter>
                    <action android:name="android.intent.action.BOOT_COMPLETED"/>
                </intent-filter>
      </receiver>
    (2)广播代码
    
    /**
     * 开机完成广播
     */
     
    public class mReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent){
            Intent mIntent = new Intent(context,StepService.class);
            context.startService(mIntent);
        }
    }



    五、保证息屏后不被释放资源杀死(WakeLock的使用)

    (1)添加权限
    
        <uses-permission android:name="android.permission.WAKE_LOCK" />
    (2)在创建Service以后调用方法
    
       /**
         * 同步方法   得到休眠锁
         * @param context
         * @return
         */
        synchronized private void getLock(Context context){
            if(mWakeLock==null){
                PowerManager mgr=(PowerManager)context.getSystemService(Context.POWER_SERVICE);
                mWakeLock=mgr.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,StepService.class.getName());
                mWakeLock.setReferenceCounted(true);
                Calendar c=Calendar.getInstance();
                c.setTimeInMillis((System.currentTimeMillis()));
                int hour =c.get(Calendar.HOUR_OF_DAY);
                if(hour>=23||hour<=6){
                    mWakeLock.acquire(5000);
                }else{
                    mWakeLock.acquire(300000);
                }
            }
            Log.v(TAG,"get lock");
        }
    (3)在onDestroy()方法中调用释放锁的方法(避免占用内存)
    
    synchronized private void releaseLock()
        {
            if(mWakeLock!=null){
                if(mWakeLock.isHeld()) {
                    mWakeLock.release();
                    Log.v(TAG,"release lock");
                }
     
                mWakeLock=null;
            }
        }

    六、启动所有Service(在Activity中)
     

     /**
         * 开启所有Service
         */
        private void startAllServices()
        {
            startService(new Intent(this, StepService.class));
            startService(new Intent(this, GuardService.class));
            if(Build.VERSION.SDK_INT >=Build.VERSION_CODES.LOLLIPOP) {
                Log.d(TAG, "startAllServices: ");
                //版本必须大于5.0
                startService(new Intent(this, JobWakeUpService.class));
            }
        }
    

    注意:该方法不能保证在所有机型上有效,而且除非在必要时,否则不建议写这样的流氓软件。特别是谷歌在android7.0以后对管理加强,想要保活Service其实已经变得不太可能了,谷歌这样做无疑是为了减少流氓软件的数量,这样做也是可取的。
    ---------------

     

    参考链接:

    关于 Android 进程保活,你所需要知道的一切http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2016/0418/4158.html

    Android进程保活招式大全 http://dev.qq.com/topic/57ac4a0ea374c75371c08ce8

    论Android应用进程长存的可行性http://blog.csdn.net/aigestudio/article/details/51348408

    Android 通过JNI实现守护进程,使Service服务不被杀死 http://mp.weixin.qq.com/s?__biz=MzI0MjE3OTYwMg==&mid=401629367&idx=1&sn=9f086cfdc00f954e21e6a6253f1ae288&scene=21#wechat_redirect


     

    展开全文
  • android服务保活

    2017-08-22 12:01:12
    Android5.0 以后系统对 Native 进程等加强了管理,Native 拉活方式失效。系统在 Android5.0 以上版本提供了 JobScheduler 接口,系统会定时调用该进程以使应用进行一些逻辑操作。方案适用范围该方案主要适用于 ...

    Android5.0 以后系统对 Native 进程等加强了管理,Native 拉活方式失效。系统在 Android5.0 以上版本提供了 JobScheduler 接口,系统会定时调用该进程以使应用进行一些逻辑操作。

    方案适用范围

    该方案主要适用于 Android5.0 以上版本手机。

    该方案在 Android5.0 以上版本中不受 forcestop 影响,被强制停止的应用依然可以被拉活,在 Android5.0 以上版本拉活效果非常好。

    仅在小米手机可能会出现有时无法拉活的问题。

    方案实现

    JobSchedulerService

    package com.aoaoyi.service;
    
    import android.annotation.TargetApi;
    import android.app.job.JobParameters;
    import android.app.job.JobService;
    import android.content.Intent;
    import android.os.Build;
    
    /**
     * Created by xy on 2016/12/2.
     */
    
    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public class JobSchedulerService extends JobService{
    
        @Override
        public boolean onStartJob(JobParameters params) {
            startMainService();
            jobFinished(params, false);
            return false;
        }
    
        @Override
        public boolean onStopJob(JobParameters params) {
            startMainService();
            return false;
        }
    
        @Override
        public void onTaskRemoved(Intent rootIntent) {
            startMainService();
        }
    
        public void startMainService(){
            startService(MainService.getIntentAlarm(this));
        }
    }

    注册JobSchedulerService

     <service
     android:name="com.aoaoyi.service.JobSchedulerService"
     android:permission="android.permission.BIND_JOB_SERVICE"
     android:enabled="true"
     android:exported="true"
     android:process=":push"/>   
    
    

    权限

    MainService
    
    
    package com.aoaoyi.service;
    
    import android.app.AlarmManager;
    import android.app.PendingIntent;
    import android.app.Service;
    import android.app.job.JobInfo;
    import android.app.job.JobScheduler;
    import android.content.ComponentName;
    import android.content.Context;
    import android.content.Intent;
    import android.os.Build;
    import android.os.IBinder;
    
    public class MainService extends Service {
    
        /**
         * 每10分钟检查一次链接状态,确保service不被杀掉
         */
        private static final int KEEP_ALIVE_INTERVAL = BuildConfig.DEBUG ? 1 * 60 * 1000 : 10 * 60 * 1000;
    
        /**
         * ACTION Start
         */
        private static final String ACTION_START = "MainService.Action.Start";
        /**
         * ACTION Alarm
         */
        private static final String ACTION_ALARM = "MainService.Action.Alarm";
        /**
         * ACTION end start
         */
        private static final String ACTION_END_START = "MainService.Action.EndStart";
    
        private boolean mIsAddAliveAlarm = false;
    
        public MainService() {
    
        }
    
        @Override
        public IBinder onBind(Intent intent) {
    
            return null;
        }
    
        @Override
        public void onCreate() {
            if (!mIsAddAliveAlarm){
                addAliveAlarm();
                mIsAddAliveAlarm = true;
            }
            super.onCreate();
        }
    
        @Override
        public int onStartCommand(Intent pIntent, int pFlags, int pStartId) {
            if (null != pIntent){
                switch (pIntent.getAction()){
                    case ACTION_START:
    
                        break;
                    case ACTION_ALARM:
    
                        break;
                    case ACTION_END_START:
    
                        break;
                }
            }
            if (!mIsAddAliveAlarm){
                addAliveAlarm();
                mIsAddAliveAlarm = true;
            }
            return START_STICKY;
        }
    
        @Override
        public void onTaskRemoved(Intent pIntent) {
            onEnd();
        }
    
        @Override
        public void onDestroy() {
            onEnd();
            super.onDestroy();
        }
    
        private void onEnd() {
            startService(getIntentEndStart(getApplicationContext()));
        }
    
    
        /**
         * 添加重复唤醒闹钟,用于不停唤起服务
         */
        private void addAliveAlarm() {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                JobInfo.Builder _Builder = new JobInfo.Builder(0, new ComponentName(getApplication(), JobSchedulerService.class));
                _Builder.setPeriodic(KEEP_ALIVE_INTERVAL);
                _Builder.setPersisted(true);
                JobScheduler _JobScheduler = (JobScheduler) getSystemService(JOB_SCHEDULER_SERVICE);
                _JobScheduler.schedule(_Builder.build());
            }else {
                PendingIntent _PendingIntent = PendingIntent.getService(this, 0, getIntentAlarm(this), PendingIntent.FLAG_UPDATE_CURRENT);
                AlarmManager _AlarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
                _AlarmManager.cancel(_PendingIntent);
                _AlarmManager.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + KEEP_ALIVE_INTERVAL, KEEP_ALIVE_INTERVAL, _PendingIntent);
            }
        }
    
        /**
         * Start
         *
         * @param pContext
         */
        public static Intent getIntentStart(Context pContext) {
            return getActionIntent(pContext, ACTION_START);
        }
    
        /**
         * Alarm
         *
         * @param pContext
         */
        public static Intent getIntentAlarm(Context pContext) {
            return getActionIntent(pContext, ACTION_ALARM);
        }
    
        /**
         * EndStart
         *
         * @param pContext
         */
        public static Intent getIntentEndStart(Context pContext) {
            return getActionIntent(pContext, ACTION_END_START);
        }
    
        /**
         * Service Intent
         *
         * @param pContext
         * @param pAction
         * @return
         */
        private static Intent getActionIntent(Context pContext, String pAction) {
            Intent _Intent = new Intent(pContext, MainService.class);
            _Intent.setAction(pAction);
            return _Intent;
        }
    
    }

    最后一步,在主Activity启动一次MainService

    startService(MainService.getIntentStart(this));
    展开全文
  • Android服务保活问题

    2019-10-27 23:28:59
    我希望做一个服务可以一直在后台运行 然后测试做了一个工程,里面有1个activity,1个service,service设置了android:process属性,和activity不在一个进程,然后整个工程只是测试里面什么功能也没有。 然后...
  • Android6.0以后,已经无法再接受到系统开机广播了,所以还没找到好的办法,除非有别的App救你一把,给你发个广播。2)当退出界面后如何保活?遍历各种网页,众说纷纭,主要有以下办法:---提高优先级,变为前台...

     最近想做一个关于后台定位的App,需要后台持续定位,所以就想到了使用Service进行定位服务,我的手机型号是华为Honor7。

    碰到以下问题:

    1)如何做到开机自启动?

    在Android6.0以后,已经无法再接受到系统开机广播了,所以还没找到好的办法,除非有别的App救你一把,给你发个广播。


    2)当退出界面后如何保活?遍历各种网页,众说纷纭,主要有以下办法:

    ---提高优先级,变为前台服务

         优点:简单方便 

         缺点:无法做到隐蔽 ,息屏后进程总是被杀死,无法抗击“一键清理”


    ---创建双进程,通过AIDL利用两个服务互相守护

         优点:有一定的作用

         缺点:息屏后进程被杀死,从网上资料了解到,Android好像刻意封闭了这种方法;同时,无法抗击“一键清理”


    ---使用AlarmManager,在服务中定时启动自己

        优点:简单

        缺点:同样面临息屏必死,无法抗击“一件清理”


    ---使用WakeLock,防止CPU休眠

        优点:-

        缺点:没看到有什么作用,汗!


    反正试了这几种方法,都没啥作用。倒是发现通过手机的“设置”》“应用管理”》选中自己的App》“电池”》“屏幕关闭后保持运行”,能够保证服务的存活。



    大家有什么方法?可以交流以下。寻寻觅觅寻不到的感觉真痛苦,大哭




      

    展开全文
  • 记一次android服务保活

    2018-05-01 23:35:21
    项目遇到后台持续任务,那一定就是service了,可是service被杀了,就会出现问题,...7.安卓系统会根据手机内存的大小限制后台运行软件的个数,所以请尽量减少后台程序。另外请勿将app至于后台时间过长避免被系统清理。

    项目遇到后台持续任务,那一定就是service了,可是service被杀了,就会出现问题,因此自网上搜索了大量的相关资料

    其中有个归纳总结不错的:

      https://mp.weixin.qq.com/s/d3scy-dC46NW9sz7wc3YLQ


     参考文中方式实现,发现notifycation的提升优先级在某些手机上消不掉,会有一个无内容的一直存在

    最后使用了1像素+守护进程唤醒

    需要注意的是国产手机客制化多样,通过手机自身设置可提高存活:

    
    1. 小米手机:请在手机设置的电量和性能中,关闭app的"神隐模式"2. 华为手机如有省电模式设置,应设置为"性能模式"。在设置-电池-锁屏清理或受保护应用里,保护或不清理
    app。另外在设置-应用管理-设置-特殊访问权限-忽略电池优化-app(容许)。
    3. vivo手机请在i管家-省电管理-后台高耗电-允许app运行。另外将app加入加速白名单。
    4. oppo手机请设置电池-关闭后台冻结。
    5. 三星手机在安装时请打开自动运行6. 魅族手机从手机屏幕右下方上划调出多任务管理-找到app-下移-点击锁定任务
    其他手机也请检查相关设置,确保系统不会限制程序后台功能,如果安装了手机卫士,手机管家类软件,请把app加入清理,加速的白名单。
    7.安卓系统会根据手机内存的大小限制后台运行软件的个数,所以请尽量减少后台程序。另外请勿将app至于后台时间过长避免被系统清理。


    展开全文
  • 原标题:Android保活从入门到放弃:乖乖引导用户加白名单吧1、引言IM在Android上的保活问题经常在即时通讯网的论坛和技术群里被讨论,自从Android 8.0后系统大大降低了后台运行应用的保活容忍度(详见《Android P正式...
  • 1、引言IM在Android上的保活问题经常在即时通讯网的论坛和技术群里被讨论,自从Android 8.0后系统大大降低了后台运行应用的保活容忍度(详见《Android P正式版即将到来:后台应用保活、消息推送的真正噩梦》),保活从...
  • 安卓Android后台保活服务Demo,多厂商免杀,适配各大手机品牌的内存清理白名单。多进程互相唤醒保活。
  • 项目中遇到一个需求,需要竟可能的上传用户的定位信息,引发了我对目前已知的保活手段的探究,同时也遇到过客户说,推送不能收到,不能像微信那样,MMP的,不想理客户 目录 一:如何创建前台服务 1.DeskService ...
  • 代码无BUG前言项目中遇到一个需求,需要竟可能的上传用户的定位信息,引发了我对目前已知的保活手段的探究,同时也遇到过客户说,推送不能收到,不能像微信那样,MMP的,不想理客户目录一:如何创建前台服务1....
  • Android process keeps alive 安卓进程保活
  • 安卓后台保活服务service,自动重启APP
  • 项目中遇到一个需求,需要竟可能的上传用户的定位信息,引发了我对目前已知的保活手段的探究,同时也遇到过客户说,推送不能收到,不能像微信那样,MMP的,不想理客户 目录 一:如何创建前台服务 1.DeskService ...
  • Android保活机制-前台服务保活探索 创建前台服务XXXService 继承Service class XXXService : Service(){ override fun onBind(intent: Intent?): IBinder? { return null } /** * {@link #START_STICKY}, ...
  • android 进程保活

    2018-10-31 17:38:11
    android 进程保活 , 保证后台提交数据的服务一 直运行
  • Android进程保活·设置前台Service,提升App进程优先级 Android进程 此文章代码Github上有提交: 首先你要知道Android中的进程以及它的优先级,下面来说明它进程 前台进程 (Foreground process) 可见进程 ...
  • 前言项目中遇到一个需求,需要竟可能的上传用户的定位信息,引发了我对目前已知的保活手段的探究,同时也遇到过客户说,推送不能收到,不能像微信那样,MMP的,不想理客户目录一:如何创建前台服务1.DeskService ...
  • Android进程保活·1像素且透明Activity提升App进程优先级 Android进程 此文章代码Github上有提交:https://github.com/NorthernBrain/processKeep_Activity 首先你要知道Android中的进程以及它的优先级,下面来说明...
  • Android进程保活·设置前台Service,提升App进程优先级 Android进程 此文章代码Github上有提交:https://github.com/NorthernBrain/processKeep_Service/tree/master 首先你要知道Android中的进程以及它的优先级,...
  • Android进程保活 Android进程 首先你要知道Android中的进程以及它的优先级,下面来说明它进程 前台进程 (Foreground process) 可见进程 (Visible process) 服务进程 (Service process) 后台进程 (Background ...
  • 安卓进程保活

    千次阅读 2020-06-10 10:13:03
    进程保活的方式安卓杀死进程的一些机制保活的一些方式一像素保活法前台服务保活安卓杀死进程的一些机制 安卓中的进程主要分为以下五种: 1、前台进程 Foreground Process 2、可见进程 Visible Process 3、服务...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 7,448
精华内容 2,979
关键字:

安卓服务保活