2

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"));

        }
    }

}
  • I can confirm that on Xiaomi devices, programming with services is a little bit trickier than with for example Samsung devices, because the in-build security app says that for default none app is allowed to restart applications/ services. Also the taskmanager kills all non-autostart-allowed services, when you klick on the (x) in the Xiaomi taskmanager... – Jonas Pfeifhofer Aug 12 '17 at 21:56

4 Answers4

0

Services always run in background ..

If in case you require to keep running services even it is been killed .. then you just need to return with START_STICKY over onStartCommand();

START_STICKY recreates Service even it is been killed by some means.

Also make sure that you don't kill services over Activity Life cycle.

You code looks good. Your service is been killing from some where else. Might be from Activity. Either check your code or put an update for that Activity class.

AndroidHacker
  • 3,596
  • 1
  • 25
  • 45
  • Hi, thanks for the feedback. I already checked my activity but nothing seem intrusive which kill my services. The only thing in mind i cant think of if MIUI task manager or architecture as it seem lots of people have a prob with it. However, some application even not famous one able to run in background flawlessly. Its frustrating....T.T – Muzaffar Mohamed Nov 23 '16 at 16:00
0

on place of your onstartCommand this:

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    Toast.makeText(getApplicationContext(), "Services Has Been Started!", Toast.LENGTH_SHORT).show();


    return START_STICKY;
}

try this:

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i("LocalService", "Received start id " + startId + ": " + intent);
// We want this service to continue running until it is explicitly
// stopped, so return sticky.
return START_STICKY;
}

and for more knowledge visit this link-services

Shashank Verma
  • 284
  • 4
  • 19
  • Thanks for the suggestion. I had tried your solution but the problem still persist. Im note sure if this related to OS or not. I found some post mention about it: http://stackoverflow.com/questions/31355084/how-to-keep-my-app-service-keep-running-even-if-app-is-closed-from-task-manger-i http://stackoverflow.com/questions/31558866/restarting-killed-stopped-by-task-killers-services-in-android-like-whatsapp However, in my case. The services still not autostarted even i enable it to autostart T.T..Im running out of option here.... – Muzaffar Mohamed Nov 23 '16 at 15:55
  • which android version you are using? – Shashank Verma Nov 25 '16 at 03:42
  • Im using Lolipop version 5.1.1 – Muzaffar Mohamed Nov 25 '16 at 06:33
0

I think i just found a solution for this problem. For Xiomi devices, we need to:

  • Granting auto start Auto-Start permission from in-build Security App.
  • Implement RECEIVE_BOOT_COMPLETED broadcast receiver which start the service when receive the intent.

I dont know why this is the solution to keep it running, but my best guess is maybe because XIOMI already modify their OS.

Tested and working on Xiomi Redmi Note 3 Pro.

UPDATE

If you uninstall the application,and install it back, it will not work anymore. The background service was no longer auto-restarted..T.T

Community
  • 1
  • 1
0

Have you tried running service in different process. It could be done this way:

<service ...
         android:process=":separate" >
    ...
</service>

The ":processname" is convention for creating new processes' names. The default process is named as your package (for example "com.myapp"), and separate process from this example could be "com.myapp:separate"

SadClown
  • 648
  • 8
  • 16