Service: is a background Service that handles work components resident in the background.

Instant messaging: Service to do the resident backend

1. Keep core services as light as possible!

Many people prefer to centralize all background operations in a single service. Create a special process for the core service, isolated from all other background operations. Tall trees catch wind, core service must be light.

Priority of process importance:

  • Foreground process: Foreground process

    1. The Activity (onResume()) the user is interacting with 2. Service foreground (startForeground()) 4. Service foreground (startForeground()) 4. (onCreate() /onStart()/onDestory()))

  • Visible process: Visible process

    1. Our Activity is in onPause() (not onStop()) 2. The Service bound to the foreground Activity

  • Service process: Service process

    Simple startService () starts

  • Background processes: Background processes

    Processes that have no direct impact on users —–Activity while onStop()

  • Empty process: Empty Process

    Components that do not contain any activity. (Android is designed with a tradeoff to make the second boot faster.)

The further a process goes, the more likely it is to be killed by the system

How to improve the priority of the process (try not to be easily killed by the system)

1. Imitate QQ to start the Activity with 1 pixel when the screen is locked.


Background: Everything dries up when your phone is locked, to save power. Listen for the lock screen broadcast. It's locked -- start this1The Activity of pixels. Listen for the lock screen, open -- end this1The Activity of pixels. To listen for the lock screen broadcast - dynamic registration.Copy the code

Key code:


public class KeepLiveActivityManager {
    private static KeepLiveActivityManager instance;
    private Context context;
    private WeakReference<Activity> activityInstance;

    public static KeepLiveActivityManager getInstance(Context context) {
        if(instance==null){
            instance = new KeepLiveActivityManager(context.getApplicationContext());
        }
        return instance;
    }
    
    private KeepLiveActivityManager(Context context) {
        this.context = context;
    }
    
    public void setKeepLiveActivity(Activity activity){
        activityInstance = new WeakReference<Activity>(activity);
    }

    public void startKeepLiveActivity(a) {
        Intent intent = new  Intent(context, KeepLiveActivity.class);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        context.startActivity(intent);
    }
    public void finishKeepLiveActivity(a) {
        if(activityInstance! =null&&activityInstance.get()! =null){ Activity activity = activityInstance.get(); activity.finish(); }}}Copy the code

public class KeepLiveActivity extends Activity {
    private static final String TAG ="KeepLive" ;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

       moveTaskToBack(true); // Press the home button to not exit the program

        Log.i(TAG,"KeepLiveActivity----onCreate");
        Window window = getWindow();
        window.setGravity(Gravity.LEFT|Gravity.TOP);
        WindowManager.LayoutParams params =window.getAttributes();
        params.height = 1;
        params.width  = 1;
        params.x = 0;
        params.y = 0;
        window.setAttributes(params);
        KeepLiveActivityManager.getInstance(this).setKeepLiveActivity(this);
    }

    @Override
    protected void onDestroy(a) {
        super.onDestroy();
        Log.i(TAG, "KeepLiveActivity----onDestroy!!!"); }}Copy the code

public class MyService extends Service {


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

    @Override
    public void onCreate(a) {
        super.onCreate();
        ScreenListener listener = new ScreenListener(this);
        listener.begin(new ScreenListener.ScreenStateListener() {
            @Override
            public void onScreenOn(a) {
                // Open the screen --finish the 1-pixel Activity
                KeepLiveActivityManager.getInstance(MyService.this).finishKeepLiveActivity();
            }

            @Override
            public void onScreenOff(a) {
                // Lock the screen -- start the Activity with one pixel
                KeepLiveActivityManager.getInstance(MyService.this).startKeepLiveActivity();
            }

            @Override
            public void onUserPresent(a) {}}); }}Copy the code
Source code address:
KeepLiveProcess

2. There may be partnerships between large App operators and phone manufacturers — whitelist

3. Dual-process daemon


When a process is killed, another process is started, listening for each other to start.Copy the code

A<—->B kill process is A kill, the essence is and kill process time race. Key code:


public class LocalService extends Service {

    public static final String ACTION_LOCAL_SERVICE = "com.haocai.app.keepliveprocess.LocalService";
    private static final String TAG = "LocalService";

    private MyServiceConnection conn;
    private MyBinder binder;
    private Intent testIntent;
    @Override
    public void onCreate(a) {
        // TODO Auto-generated method stub
        super.onCreate();
        if(binder ==null){
            binder = new MyBinder();
        }
        conn = new MyServiceConnection();
    }

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

    @Override
    public void onDestroy(a) {
        super.onDestroy();

        if(testIntent! =null){
            stopService(testIntent);
        }

        //unbindService(conn);

    }

    // Start the foreground process to increase the importance priority
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        LocalService.this.bindService(new Intent(LocalService.this, RemoteService.class), conn, Context.BIND_IMPORTANT);

        PendingIntent contentIntent = PendingIntent.getService(this.0, intent, 0);
        NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
        builder.setTicker("360")
                .setContentIntent(contentIntent)
                .setContentTitle("I'm 360. Who am I afraid of?")
                .setAutoCancel(true)
                .setContentText("hehehe")
                .setWhen( System.currentTimeMillis());

        // Set the service to the foreground to prevent the mobile system from killing the service automatically.
        startForeground(startId, builder.build());
        return START_STICKY;
    }




    class MyBinder extends RemoteConnection.Stub{

        @Override
        public String getProcessName(a) throws RemoteException {
            // TODO Auto-generated method stub
            return "LocalService"; }}class MyServiceConnection implements ServiceConnection {

        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {

            Log.i(TAG, "Connection established successfully!");

        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            Log.i(TAG, "Local service is down ~~~~~ disconnect!");
            Toast.makeText(LocalService.this."Disconnect", Toast.LENGTH_SHORT).show();
            // Start the killed
            testIntent = new Intent();
            // Custom Service action
            testIntent.setAction(RemoteService.ACTION_REMOTE_SERVICE);
            // Define the package name of the Service
            testIntent.setPackage(getPackageName());
            Log.i("999", getPackageName() + "");
            startService(testIntent);

            LocalService.this.bindService(new Intent(LocalService.this, RemoteService.class), conn, Context.BIND_IMPORTANT); }}}Copy the code

public class RemoteService  extends Service {

    private static final String TAG = "RemoteService";
    private MyBinder binder;
    private MyServiceConnection conn;
    public static final String ACTION_REMOTE_SERVICE = "com.haocai.app.keepliveprocess.RemoteService";
    private Intent  testIntent;
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return binder;
    }

    @Override
    public void onCreate(a) {
        super.onCreate();
        if(binder == null){
            binder = new MyBinder();
        }
         conn = new MyServiceConnection();
    }

    @Override
    public void onDestroy(a) {
        super.onDestroy();
// if(testIntent! =null){
// stopService(testIntent);
/ /}
        //unbindService(conn);

    }

    // Start the foreground process to increase the importance priority
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        RemoteService.this.bindService(new Intent(RemoteService.this, LocalService.class), conn, Context.BIND_IMPORTANT);

        PendingIntent contentIntent = PendingIntent.getService(this.0, intent, 0);
        NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
        builder.setTicker("360")
                .setContentIntent(contentIntent)
                .setContentTitle("I'm 360. Who am I afraid of?")
                .setAutoCancel(true)
                .setContentText("hehehe")
                .setWhen( System.currentTimeMillis());

        // Set the service to the foreground to prevent the mobile system from killing the service automatically.
        startForeground(startId, builder.build());
        return START_STICKY;
    }


    class  MyBinder extends  RemoteConnection.Stub{

        @Override
        public String getProcessName(a) throws RemoteException {
            return "RemoteService"; }}class MyServiceConnection implements ServiceConnection{
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.i(TAG,"RemoteService successfully established connection!");
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            Log.i(TAG,"Remote service is down ~~~~~ disconnect!");
            Toast.makeText(RemoteService.this."Disconnect",Toast.LENGTH_SHORT).show();


            // Start the killed
            testIntent = new Intent();
            // Custom Service action
            testIntent.setAction(LocalService.ACTION_LOCAL_SERVICE);
            // Define the package name of the Service
            testIntent.setPackage(getPackageName());
            Log.i("999",getPackageName()+"");
            startService(testIntent);

            RemoteService.this.bindService(new Intent(RemoteService.this, LocalService.class), conn, Context.BIND_IMPORTANT); }}}Copy the code
Source code address:
KeepLiveProcess2

4.JobScheduler

Add the task to the system scheduling queue, and it will be executed when the task window is reached. We can start our process in this task. This can achieve nearly unkillable process.


@SuppressLint("NewApi")
public class JobHandleService extends JobService{
    public static final String ACTION_JOB_HANDLE_SERVICE = "com.haocai.app.keepliveprocess.JobHandleService";
    private int kJobId = 0;
    @Override
    public void onCreate(a) {
        super.onCreate();
        Log.i("INFO"."jobService create");

    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.i("INFO"."jobService start");
        scheduleJob(getJobInfo());
        return START_NOT_STICKY;
    }

    @Override
    public void onDestroy(a) {
        // TODO Auto-generated method stub
        super.onDestroy();
    }

    @Override
    public boolean onStartJob(JobParameters params) {
        // TODO Auto-generated method stub
        Log.i("INFO"."job start");
// scheduleJob(getJobInfo());
        boolean isLocalServiceWork = isServiceWork(this, LocalService.ACTION_LOCAL_SERVICE);
        boolean isRemoteServiceWork = isServiceWork(this, RemoteService.ACTION_REMOTE_SERVICE);
// Log.i("INFO", "localSericeWork:"+isLocalServiceWork);
// Log.i("INFO", "remoteSericeWork:"+isRemoteServiceWork);
        if(! isLocalServiceWork|| ! isRemoteServiceWork){//this.startService(new Intent(this,LocalService.class));
            startLocalService();
            startRemoteService();
            //this.startService(new Intent(this,RemoteService.class));
            Toast.makeText(this."process start", Toast.LENGTH_SHORT).show();
        }
        return true;
    }


    private void startLocalService(a){
        Intent  testIntent = new Intent();

        // Custom Service action
        testIntent.setAction(LocalService.ACTION_LOCAL_SERVICE);
        // Define the package name of the Service
        testIntent.setPackage(getPackageName());
        Log.i("999",getPackageName()+"");
        startService(testIntent);
    }
    private void  startRemoteService(a){
        Intent testIntent = new Intent();

        // Custom Service action
        testIntent.setAction(RemoteService.ACTION_REMOTE_SERVICE);
        // Define the package name of the Service
        testIntent.setPackage(getPackageName());
        Log.i("999", getPackageName() + "");
        startService(testIntent);

    }

    @Override
    public boolean onStopJob(JobParameters params) {
        Log.i("INFO"."job stop");
// Toast.makeText(this, "process stop", Toast.LENGTH_SHORT).show();
        scheduleJob(getJobInfo());
        return true;
    }

    /** Send job to the JobScheduler. */
    public void scheduleJob(JobInfo t) {
        Log.i("INFO"."Scheduling job");
        JobScheduler tm =
                (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE);
        tm.schedule(t);
    }

    public JobInfo getJobInfo(a){
        JobInfo.Builder builder = new JobInfo.Builder(kJobId++, new ComponentName(this, JobHandleService.class));
        builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY);
        builder.setPersisted(true);
        builder.setRequiresCharging(false);
        builder.setRequiresDeviceIdle(false);
        builder.setPeriodic(10);// Interval time -- cycle
        return builder.build();
    }


    /** * A way to determine if a service is running **@param mContext
     * @paramServiceName * is the class name of the package name + service (such as.net. Loonggg. Testbackstage. TestService) *@returnTrue indicates that the service is running, false indicates that the service is not running */
    public boolean isServiceWork(Context mContext, String serviceName) {
        boolean isWork = false;
        ActivityManager myAM = (ActivityManager) mContext
                .getSystemService(Context.ACTIVITY_SERVICE);
        List<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; }}returnisWork; }}Copy the code

      <service
            android:name=".JobHandleService"
            android:permission="android.permission.BIND_JOB_SERVICE">
        </service>
Copy the code

5. Monitor the broadcasts of QQ, wechat, system applications, Umeng, Miui push and so on, and then start myself.

6. Wake up our processes using account synchronization

AccountManager

7.NDK to solve, Native process to achieve dual process daemon.