Im new in developing an Android application for my college final year project. Recently, i tried to create an android aplication which can run services in background even if my activity has been cleared or closed, for example via recent activity.
What i have done, but still failed:
- Tried to return START_STICKY;
- Tried to use AlamManager to rechedule restart for services.
I noticed that this problem only occurs within new devices. My services running fine in emulator,but not in real device. Im using Xiomi Redmi Note 3 (Lolipop), and im well aware on its inbuild task manager. However, android still kill my background services even i enable/permit autostart for my apps.
I tested several other application, for example whatssup and even several non-popular apps from playstore (I already permit autostart permission).They can automatically "restart" the services as usual.
I already do a lot of research about this, and so far had found no real solution for it.
This is my service code so far:
package com.muzaffar.myApps.App;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.IBinder;
import android.os.SystemClock;
import android.widget.Toast;
import com.muzaffar.myApps.Lib.PhoneInfo;
import java.util.concurrent.TimeUnit;
public class myAppsServices extends Service {
private static final int FIRST_RUN_TIMEOUT_MILISEC = 5 * 1000;
private static final int SERVICE_STARTER_INTERVAL_MILISEC = 1 * 1000;
private static final int SERVICE_TASK_TIMEOUT_SEC = 10;
private final int REQUEST_CODE = 1;
private AlarmManager serviceReStarterAlarmManager = null;
private MyTask asyncTask = null;
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
// Start of timeout-autostarter for our service (watchdog)
startServiceReStarter();
// Start performing service task
serviceTask();
/*Toast.makeText(this, "Service Started!", Toast.LENGTH_LONG).show();*/
}
/***
* _____ _
* / ____| (_)
* | (___ ___ _ __ __ __ _ ___ ___ ___
* \___ \ / _ \| '__|\ \ / /| | / __|/ _ \/ __|
* ____) || __/| | \ V / | || (__| __/\__ \
* |_____/ \___||_| \_/ |_| \___|\___||___/
*
* http://patorjk.com/software/taag/#p=display&h=1&v=0&c=c&f=Big&t=Shared%20Pref
*/
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Toast.makeText(getApplicationContext(), "Services Has Been Started!", Toast.LENGTH_SHORT).show();
return START_STICKY;
}
/***
* _____ _ _ __ _ _ _ __ __
* | __ \ | | | |/ /(_)| || || \/ |
* | | | | ___ _ __ | |_ | ' / _ | || || \ / | ___
* | | | | / _ \ | '_ \ | __| | < | || || || |\/| | / _ \
* | |__| || (_) || | | || |_ | . \ | || || || | | || __/
* |_____/ \___/ |_| |_| \__| |_|\_\|_||_||_||_| |_| \___|
*
*
*/
private void StopPerformingServiceTask() {
asyncTask.cancel(true);
}
@Override
public void onDestroy() {
// performs when user or system kill our service
/*Toast.makeText(getApplicationContext(),"Services Has Been Destroyed!",Toast.LENGTH_SHORT).show();*/
StopPerformingServiceTask();
}
private void serviceTask() {
asyncTask = new MyTask();
asyncTask.execute();
}
class MyTask extends AsyncTask<Void, Void, Void> {
@Override
protected Void doInBackground(Void... params) {
try {
for (;;) {
TimeUnit.SECONDS.sleep(SERVICE_TASK_TIMEOUT_SEC);
// check does performing of the task need
if(isCancelled()) {
break;
}
// Initiating of onProgressUpdate callback that has access to UI
publishProgress();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
}
@Override
protected void onProgressUpdate(Void... progress) {
super.onProgressUpdate(progress);
//Toast.makeText(getApplicationContext(), "Please dont kill me, Im tired dying...T.T", Toast.LENGTH_LONG).show();
}
}
// We should to register our service in AlarmManager service
// for performing periodical starting of our service by the system
private void startServiceReStarter() {
Intent intent = new Intent(this, ServiceStarter.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, this.REQUEST_CODE, intent, 0);
if (pendingIntent == null) {
/*Toast.makeText(this, "Some problems with creating of PendingIntent", Toast.LENGTH_LONG).show();*/
} else {
if (serviceReStarterAlarmManager == null) {
serviceReStarterAlarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
serviceReStarterAlarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME,
SystemClock.elapsedRealtime() + FIRST_RUN_TIMEOUT_MILISEC,
SERVICE_STARTER_INTERVAL_MILISEC, pendingIntent);
}
}
}
}
My Activity code
package com.muzaffar.myApps.App;
import android.app.ActivityManager;
import android.app.admin.DevicePolicyManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.graphics.Color;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import com.muzaffar.spycare.App.SpycareServices;
import com.muzaffar.spycare.App.Util;
import com.muzaffar.spycare.R;
import com.muzaffar.spycare.Receiver.DeviceAdmin;
/**
* Created by OligoCoco on 11/2/2016.
*/
public class Main_Activity extends AppCompatActivity implements View.OnClickListener {
//Default PIN
public static final String DEFAULT_PIN = "1234";
//Import Instance Shared Pref
Util myPref=new Util(Main_Activity.this);
//ImportButton
Button btn_setting, btn_Stealth, btn_Test_Page;
public static Button btn_device_manager;
TextView txt_Start_Stop;
private boolean isRunning = false;
private EditText SecretCode;
String device_admin;
//Enable Device Admin
private ComponentName deviceAdmin;
private DevicePolicyManager devicePolicyManager;
private static final int REQUEST_CODE_ENABLE_ADMIN = 1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
/*Initialize*/
deviceAdmin = new ComponentName(getApplicationContext(), DeviceAdmin.class);
devicePolicyManager = (DevicePolicyManager) getSystemService(DEVICE_POLICY_SERVICE);
/*Initialize Button*/
txt_Start_Stop = (TextView) findViewById(R.id.app_start_stop);
/*Return default status of txt_Start_Stop*/
showServiceStatus();
btn_setting = (Button) findViewById(R.id.app_setting);
btn_setting.setOnClickListener(this);
btn_device_manager = (Button) findViewById(R.id.app_device_manager);
device_admin = myPref.getSavedShared("device_admin");
if(device_admin==null || device_admin.equals("false") || device_admin.equals("")){
btn_device_manager.setText(R.string.app_device_manager);
btn_device_manager.setClickable(true);
btn_device_manager.setEnabled(true);
}else{
btn_device_manager.setText(R.string.app_device_manager_activated);
btn_device_manager.setClickable(false);
btn_device_manager.setEnabled(false);
}
btn_device_manager.setOnClickListener(this);
btn_Stealth = (Button) findViewById(R.id.app_start_stealth);
btn_Stealth.setOnClickListener(this);
SecretCode = (EditText) findViewById(R.id.app_secret_code);
SecretCode.setTextColor(Color.LTGRAY);
SecretCode.setText(myPref.getSavedShared("Secret_Code"));
//Start Services
startMonitoring();
//Request on potret
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
@Override
public void onStop(){
super.onStop();
myPref.saveToPref("Secret_Code",SecretCode.getText().toString());
final int flags = DevicePolicyManager.RESET_PASSWORD_REQUIRE_ENTRY;
if (devicePolicyManager.isAdminActive(deviceAdmin)) {
devicePolicyManager.resetPassword(myPref.getSavedShared("Secret_Code"), flags);
}
}
/***
* _____ _ __ __
* | __ \ (_) | \/ |
* | | | | ___ __ __ _ ___ ___ | \ / | __ _ _ __ __ _ __ _ ___ _ __
* | | | | / _ \\ \ / /| | / __|/ _ \ | |\/| | / _` || '_ \ / _` | / _` | / _ \| '__|
* | |__| || __/ \ V / | || (__| __/ | | | || (_| || | | || (_| || (_| || __/| |
* |_____/ \___| \_/ |_| \___|\___| |_| |_| \__,_||_| |_| \__,_| \__, | \___||_|
* __/ |
* |___/
*/
/*Device Manager*/
private void lock() {
devicePolicyManager.setPasswordQuality(deviceAdmin, DevicePolicyManager.PASSWORD_QUALITY_NUMERIC);
devicePolicyManager.setPasswordMinimumLength(deviceAdmin, 4);
final int flags = DevicePolicyManager.RESET_PASSWORD_REQUIRE_ENTRY;
devicePolicyManager.resetPassword(myPref.getSavedShared("Secret_Code"), flags);
}
@Override
protected void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_CODE_ENABLE_ADMIN && resultCode == RESULT_OK) {
btn_device_manager.setText(this.getString(R.string.app_device_manager_activated));
btn_device_manager.setClickable(false);
btn_device_manager.setEnabled(false);
lock();
}else{
btn_device_manager.setText(this.getString(R.string.app_device_manager));
btn_device_manager.setClickable(true);
btn_device_manager.setEnabled(true);
}
}
/***
* _____ _ __ __ _ _ _
* / ____| | | | \/ | | | | | | |
* | | _ _ ___ | |_ ___ _ __ ___ | \ / | ___ | |_ | |__ ___ __| |
* | | | | | |/ __|| __|/ _ \ | '_ ` _ \ | |\/| | / _ \| __|| '_ \ / _ \ / _` |
* | |____| |_| |\__ \| |_| (_) || | | | | | | | | || __/| |_ | | | || (_) || (_| |
* \_____|\__,_||___/ \__|\___/ |_| |_| |_| |_| |_| \___| \__||_| |_| \___/ \__,_|
*
*
*/
/*Function to listen which button has been clicked and response correspondingly*/
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.app_device_manager:
defaultPIN();
if (devicePolicyManager.isAdminActive(deviceAdmin)) {
//If device admin is active
} else {
// Launch the activity to have the user enable our admin.
Intent intent = new Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN);
intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, deviceAdmin);
startActivityForResult(intent, REQUEST_CODE_ENABLE_ADMIN);
myPref.saveToPref("device_admin", "true");
}
break;
case R.id.app_setting:
defaultPIN();
Intent a = new Intent(getApplicationContext(), Setting_Activity.class);
startActivity(a);
break;
case R.id.app_start_stealth:
defaultPIN();
Intent b = new Intent(Intent.ACTION_MAIN);
b.addCategory(Intent.CATEGORY_HOME);
b.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(b);
break;
}
}
/*Function used to start the monitoring process*/
private void startMonitoring() {
//startService(new Intent(this, SpycareServices.class));
startService(new Intent(this, SpycareServices.class));
}
/*Function used to stop the monitoring process*/
private void stopMonitoring() {
//stopService(new Intent(this, SpycareServices.class));
stopService(new Intent(this, SpycareServices.class));
}
/*Function to change button status*/
private void showServiceStatus(){
// Show the current service state
/*if(isMyServiceRunning(SpycareServices.class,getApplicationContext())){*/
if(isMyServiceRunning(SpycareServices.class,getApplicationContext())){
txt_Start_Stop.setText(this.getString(R.string.stop_label));
txt_Start_Stop.setTextColor(Color.BLUE);
isRunning = true;
}else{
txt_Start_Stop.setText(this.getString(R.string.start_label));
txt_Start_Stop.setTextColor(Color.RED);
isRunning = false;
//If service not running
startMonitoring();
//Return
Intent a = new Intent(getApplicationContext(), Main_Activity.class);
startActivity(a);
}
}
/*Function to check if certain services is running*/
private boolean isMyServiceRunning(Class<?> serviceClass,Context context) {
ActivityManager manager = (ActivityManager)context. getSystemService(Context.ACTIVITY_SERVICE);
for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
if (serviceClass.getName().equals(service.service.getClassName())) {
return true;
}
}
return false;
}
/*Function to place default PIN*/
public void defaultPIN(){
String compA = myPref.getSavedShared("Secret_Code");
if(compA.isEmpty()){
Toast.makeText(getApplicationContext(), "PIN Cannot be empty, Applying default PIN "+DEFAULT_PIN, Toast.LENGTH_SHORT).show();
myPref.saveToPref("Secret_Code",DEFAULT_PIN);
//Set DMP Pass
final int flags = DevicePolicyManager.RESET_PASSWORD_REQUIRE_ENTRY;
if (devicePolicyManager.isAdminActive(deviceAdmin)) {
devicePolicyManager.resetPassword(DEFAULT_PIN, flags);
}
SecretCode.setText(myPref.getSavedShared("Secret_Code"));
}
}
}