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:
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"/>
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"/>
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"); } }
<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.