Process keep alive

The process of keeping alive is quite pitiful. Before android system 5.0, many programmers used android loopholes to keep alive, but since android system 5.0, many apps may be killed, and dual-process guarding can no longer satisfy the process. Keep alive, I checked a lot of information and tested it, and found that these answers can no longer meet the process guarding problem after 5.0. But after the android5.0 system, JobService and JobScheduler are provided, and we can use JobScheduler to keep alive:

1. Be a dual-process daemon
Local service:

public class LocalService extends Service {
    private MyBinder binder;
    private MyServiceConnection conn;
    private PendingIntent pIntent;

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

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

    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        /**
         * Connect to remote services
         */
        this.bindService(new Intent(this, RemoteService.class), conn, Context.BIND_IMPORTANT);
        //Improve the service priority to avoid too many being killed, adopt the 360 ​​method
        return START_STICKY;
    }

    class MyBinder extends IMyAidlInterface.Stub{
        @Override
        public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {

        }
    }

    class MyServiceConnection implements ServiceConnection {
        //connection succeeded
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {

        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            //Indicate that the remote service is hung up
            LocalService.this.startService(new Intent(LocalService.this, RemoteService.class));
            //connect to remote service
            LocalService.this.bindService(new Intent(LocalService.this, RemoteService.class), conn, Context.BIND_IMPORTANT);
        }
    }
}

Remote process: The code of the local service and the remote service is the same, just to verify the process daemon

public class RemoteService extends Service {
    private MyBinder binder;
    private MyServiceConnection conn;
    private PendingIntent pIntent;

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

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

    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        /**
         * Connect to local services
         *
         * The parameter Context.BIND_IMPORTANT specifies the binding identifier, which can improve the priority of the service
         * Android 4.0 (API 14) introduces some new identifiers:
         * 1. The priority of BIND_ADJUST_WITH_ACTIVITY Service will be relative to the Activity it is bound to. If the Activity goes to the foreground, the priority of the Service will be relatively improved, and if the Activity goes to the background, the priority of the Servcie will be relatively lowered.
         * 2.BIND_ABOVE_CLIENT and BIND_IMPORTANT When your client is in the foreground, the Service under this identifier also becomes as important as the Activity in the foreground, and the priority increases rapidly. If it is BIND_ABOVE_CLIENT, the priority has exceeded Activity, that is to say, Activity will die before Service, when resources are not enough.
         * 3.BIND_NOT_FOREGROUND The priority of the Service you bind will never be higher than the foreground Activity.
         * 4.BIND_WAIVE_PRIORITY The bound service cannot adjust its own priority.
         */
        this.bindService(new Intent(this, LocalService.class), conn, Context.BIND_IMPORTANT);
        //Don't return super.onStartCommand(...), also to increase the priority and avoid being cleaned up
        return START_STICKY;
    }

    class MyBinder extends IMyAidlInterface.Stub{
        @Override
        public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {

        }
    }

    class MyServiceConnection implements ServiceConnection {
        //connection succeeded
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {

        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            //Resurrection local service
            RemoteService.this.startService(new Intent(RemoteService.this, LocalService.class));
            //connect to local service
            RemoteService.this.bindService(new Intent(RemoteService.this, LocalService.class), conn, Context.BIND_IMPORTANT);
        }
    }
}


Configure these two services in the manifest file respectively. The attribute android:process=":remote" configured in the manifest file can specify a process for any component and application.

        <service
            android:name="com.zc9000.vpn.VPNService"
            android:enabled="true" />
        <service android:name="com.service.LocalService"/>
        <service android:name="com.service.RemoteService"
                 android:process=":remote"/>


The above two-process binding can only realize the restart when a single process is killed. If two processes are killed at the same time, the guardianship of the process cannot be realized.
JobScheduler and JobSerVice can be used together to restart the process
JobService uses ADIL+Handler to deliver messages
Code display: onstopJob is called after the dual process is killed, so we can restart the remote service and the local service that are killed at the same time


@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public class JobHandleService extends JobService {
    private int kJobId = 0;

    @Override
    public void onCreate() {
        super.onCreate();
        Log.e("TAG", "jobService create");
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.e("TAG", "jobService start");
        //Start our service in this way
        scheduleJob(getJobInfo());
        return START_NOT_STICKY;
    }

    @Override
    public boolean onStartJob(JobParameters params) {
        Log.e("TAG555", "job start");
        boolean isLocalServiceWork = isServiceWork(this, "com.service.LocalService");
        boolean isRemoteServiceWork = isServiceWork(this, "com.service.RemoteService");
        Log.i("isIMServiceWork",isIMServiceWork+"---"+isVPNServiceWork);
        if (!isLocalServiceWork || !isRemoteServiceWork){
            this.startService(new Intent(this, LocalService.class));
            this.startService(new Intent(this, RemoteService.class));
            HooliganActivity. startHooligan();

            Toast.makeText(this, "process start", Toast.LENGTH_LONG).show();
        }
        return true;
    }

    @Override
    public boolean onStopJob(JobParameters params) {
        Log.e("TAG", "job stop");
        scheduleJob(getJobInfo());
        return true;
    }

    public void scheduleJob(JobInfo t){
        Log.e("TAG", "Scheduling job");
        JobScheduler tm = (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE);
        tm.schedule(t);
    }

    public JobInfo getJobInfo(){
        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);
        return builder.build();
    }

    /**
     * A method to determine whether a service is running
     * @param mContext
     * @param serviceName is the package name + the class name of the service (eg: net.loonggg.testbackstage.TestService)
     * @return true means it is running, false means the service is not running
     */
    public boolean isServiceWork(Context mContext, String serviceName){
        boolean isWork = false;
        ActivityManager myAM = (ActivityManager) mContext.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;
    }
}


It is necessary to restart the process during initialization, so we have to start our process in the interface that will go every time we kill it.
Here I do this enabled service in the welcome interface and configure it in onCreate()
JobScheduler is the scheduling class of Job, which is responsible for executing and canceling tasks and other logic.


@Override
	protected void onCreate(Bundle arg0) {
		super.onCreate(arg0);
		setContentView(R.layout.em_activity_splash);
		rootLayout = (RelativeLayout) findViewById (R.id.splash_root);
		versionText = (TextView) findViewById(R.id.tv_version);
		this.startService(new Intent(this, JobHandleService.class));
		this.startService(new Intent(this, LocalService.class));
		this.startService(new Intent(this, RemoteService.class));
		if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
			JobScheduler jobScheduler = (JobScheduler) getSystemService(JOB_SCHEDULER_SERVICE);
			JobInfo jobInfo = new JobInfo.Builder(1, new ComponentName(getPackageName(), JobHandleService.class.getName()))
					.setPeriodic (10)
					.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
					.build();
			jobScheduler.schedule(jobInfo);
		}

	}

@Override
	protected void onCreate(Bundle arg0) {
		super.onCreate(arg0);
		setContentView(R.layout.em_activity_splash);
		rootLayout = (RelativeLayout) findViewById (R.id.splash_root);
		versionText = (TextView) findViewById(R.id.tv_version);
		this.startService(new Intent(this, JobHandleService.class));
		this.startService(new Intent(this, LocalService.class));
		this.startService(new Intent(this, RemoteService.class));
		if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
			JobScheduler jobScheduler = (JobScheduler) getSystemService(JOB_SCHEDULER_SERVICE);
			JobInfo jobInfo = new JobInfo.Builder(1, new ComponentName(getPackageName(), JobHandleService.class.getName()))
					.setPeriodic (10)
					.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
					.build();
			jobScheduler.schedule(jobInfo);
		}

	}
 After declaring the JobService, we also need to configure it in the manifest file
The configuration of android:permission="android.permission.BIND_JOB_SERVICE" is necessary. If this configuration is missing, permission problems will be reported.


   <service
            android:name="com.service.JobHandleService"
            android:enabled="true"
            android:exported="true"
            android:permission="android.permission.BIND_JOB_SERVICE">
        </service>


Speaking of permissions, we must remember to configure permissions in the manifest file


<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>

The above method has basically guaranteed the process of keeping alive, but keeping the process alive does not mean that the process you started is no problem. Yes, I found that the process was started during use, but don't send me a message. When the news came, I still couldn't receive the information I needed. In the review of the data, I found that the black technology generated by QQ uses 1 pixel keep-alive, so can we also open a transparent page to keep it alive? live? Open a transparent activity, the main thread is opened, the main thread is opened, and the whole service is not started up, we can open a transparent interface to restart the process, and the interface is transparent, so it is not necessary to open the program. will be discovered.
The code is as follows: we call him a pixel keep alive


public class HooliganActivity extends Activity {
    private static HooliganActivity instance;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate (savedInstanceState);
        System.out.println("HooliganActivity onCreate");
    //    Toast.makeText(this,"HooliganActivity onCreate", Toast.LENGTH_SHORT).show();
        instance = this;
        Window window = getWindow();
        window.setGravity(Gravity.LEFT | Gravity.TOP);
        WindowManager.LayoutParams params = window.getAttributes();
        params.x = 0;
        params.y = 0;
        params.height = 1;
        params.width = 1;
        window.setAttributes(params);
        onDestroy ();
    }

    /**
     * Open the keep alive page
     */
    public static void startHooligan() {
      //  Toast.makeText(PChatApplication.getInstance(),"startHooligan", Toast.LENGTH_SHORT).show();
        Intent intent = new Intent(PChatApplication.getInstance(), HooliganActivity.class);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        //intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
       // intent.putExtra("finishApp", true);
        PChatApplication.getInstance().startActivity(intent);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy ();
        System.out.println("HooliganActivity onDestroy");
       // Toast.makeText(this,"HooliganActivity onDestroy", Toast.LENGTH_SHORT).show();

        instance = null;
        Intent intent= new Intent(Intent.ACTION_MAIN);

        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); //If it is called in the service, the new task identifier must be added

        intent.addCategory(Intent.CATEGORY_HOME);

        startActivity(intent);
    }

    /**
     * Close the keep alive page
     */
    public static void killHooligan() {

        if(instance != null) {
     //   Toast.makeText(PChatApplication.getInstance(),"killHooligan", Toast.LENGTH_SHORT).show();
            instance.finish();

        }
    }

    @Override
    protected void onResume() {
        super.onResume();
        System.out.println("HooliganActivity onResume");
    }
}


The transparent interface is turned on, and it also blocks our click events. When thinking or thinking, we can directly return to the main page by dropping the home button, and the code is in the transparent interface.
Many people have a habit of long-pressing the android home button and then clearing the application you just watched. The function of the attribute android:excludeFromRecents="true" is to hide it from the pop-up application list when you long-press the home button. Your application, to achieve the purpose of hiding the application.
The android:exported="false" attribute is added to prevent external calls, prevent specific sensitive operations or phishing deception, and add permissions when calling

In an activity whose android:finishOnTaskLaunch attribute is true, press the home button to return to the [home screen] screen, and then click the icon of the application to start the program, the system will call the activity's [onDestroy] to destroy. Because when you click the application's icon to start the program, the task is restarted.

For one pixel it is inevitable:
    <activity
            android:name="com.service.HooliganActivity"
            android:configChanges="keyboardHidden|orientation|screenSize|navigation|keyboard"
            android:excludeFromRecents="true"
            android:exported="false"
            android:finishOnTaskLaunch="false"
            android:launchMode="singleInstance"
            android:theme="@style/HooliganActivityStyle"/>


style:


   <style name="HooliganActivityStyle">
        <item name="android:windowBackground">@color/transparent</item>
        <item name="android:windowContentOverlay">@null</item>
        <item name="android:windowIsTranslucent">true</item>
        <item name="android:windowNoDisplay">false</item>
        <item name="android:windowDisablePreview">true</item>
    </style>

Implementing the above can ensure the keep alive of some mobile phones, and the other part is that different mobile phone manufacturers have made different changes to the source code, so this code is not available for different mobile phones.



Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324888358&siteId=291194637