As my title says, I have a FOREGROUNDSERVICE
which is stopped after around 3 minutes (I guess doze mode), and stops acquiring Accelerometry. I do use a PARTIAL_WAKE_LOCK
and return START_STICKY
... but I don't undestand the reason why this happens. I do really need Acc to not stop recording and log the values on a file... The way to stop the acquisition would be a battery check, a free space check or a button click on the app.
I tested the implementation below application on an Android 6.0.1 (API 23), and worked like charm. When testing the same application on a Xiaomi Pocophone Android 10 device (API 29), after 3 minutes the doze mode (I guess) kicks in and stops the acc acqquisition...
Any ideas of why? In theory a foreground service should keep the CPU running, and with the partial wake_lock I should ensure it keeps running and acquiring ACC...
Here there is my service:
public class AccelerometryService extends Service implements SensorEventListener {
// WakeLock variable to keep CPU running obtaining Acc
private PowerManager.WakeLock wakeLock;
//Notification Variable to show that Acc has started
private NotificationChannel notChannel = null;
private NotificationManager nMservice = null;
Intent notifIntent = null;
PendingIntent pendingIntent = null;
private int NOTIFICATION = 112020592;
private String channelID = "AccRecordService";
//Accelerometry variables
private SensorManager sensorManager = null;
private Sensor sensor = null;
//File Writting
private long SystemTime = 0;
private File rawDataFolder = null;
private String FileName = null;
private File rawDataTxt = null;
private FileOutputStream fileOutputStream = null;
//Acc data sharing
private Observable oString = null;
public static final String ACCNOTIFICATION = "com.example.android.sleeppos";
@SuppressLint("WakelockTimeout")
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
Toast.makeText(this, "Logging service started new", Toast.LENGTH_SHORT).show();
//Acquire wake lock
PowerManager pm = (PowerManager) this.getSystemService(Context.POWER_SERVICE);
this.wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "WLTAG:MyWakelockTag");
wakeLock.acquire();
//Display notification
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
createNotificationChannel(this.channelID, "AccBackgroundService");
}
this.notifIntent = new Intent(this, MainActivity.class);
this.pendingIntent = PendingIntent.getActivity(this, 0, this.notifIntent, 0);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
Notification.Builder builder = new Notification.Builder(this, this.channelID)
.setSmallIcon(R.drawable.ic_launcher_background)
.setContentTitle("SleepPos app")
.setContentText("Acc has started being recorded")
.setVisibility(Notification.VISIBILITY_PUBLIC)
.setContentIntent(this.pendingIntent)
.setOngoing(true);
startForeground(this.NOTIFICATION, builder.build());
} else {
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, this.channelID)
.setSmallIcon(R.drawable.ic_launcher_background)
.setContentTitle("SleepPos app")
.setContentText("Acc has started being recorded")
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
.setContentIntent(this.pendingIntent)
.setOngoing(true);
startForeground(this.NOTIFICATION, builder.build());
}
// register Acc listener
sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
sensorManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_FASTEST);
//Parse variables given from the intent
this.rawDataFolder = (File) intent.getExtras().get("DataFolder");
this.FileName = intent.getStringExtra("FileName");
this.SystemTime = intent.getLongExtra("SystemTime", 0);
this.rawDataTxt = new File(this.rawDataFolder, this.FileName);
try {
this.rawDataTxt.createNewFile();
this.fileOutputStream = new FileOutputStream(this.rawDataTxt);
this.fileOutputStream.write(("Time_elapsed_(nanoseconds);X-Axis;Y-Axis;Z-Axis" + System.lineSeparator()).getBytes());
} catch (IOException ioe) {
Log.v("ErrorFile", "Error while creating empty file:");
}
return START_STICKY;
}
@Override
public void onCreate() {
super.onCreate();
}
@Override
public void onDestroy() {
super.onDestroy();
//unregister sensor listener
sensorManager.unregisterListener(this);
//cancel notification
stopForeground(true);
//Close the file being used to register Acc
try {
this.fileOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
//release wakeLock
wakeLock.release();
Log.v("DEBUG_SLEEPPOS","onDestroyDone");
//Stop Service
stopSelf();
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onSensorChanged(SensorEvent event) {
// grab the values and timestamp -- off the main thread
long dataTime = event.timestamp;
// Call the file handle to write
try {
String delimiter = ";";
fileOutputStream.write(((dataTime - AccelerometryService.this.SystemTime) + delimiter +
event.values[0] + delimiter +
event.values[1] + delimiter +
event.values[2] +
System.lineSeparator()).getBytes());
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
@RequiresApi(Build.VERSION_CODES.O)
private void createNotificationChannel(String channelId, String channelName) {
this.notChannel = new NotificationChannel(channelId, channelName, NotificationManager.IMPORTANCE_HIGH);
this.notChannel.enableLights(true);
this.notChannel.setLightColor(Color.RED);
this.notChannel.enableVibration(true);
long[] Vibrations = {100, 200, 300, 400, 500, 400, 300, 200, 400};
this.notChannel.setVibrationPattern(Vibrations);
this.notChannel.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC);
this.notChannel.setImportance(NotificationManager.IMPORTANCE_HIGH);
this.nMservice = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
this.nMservice.createNotificationChannel(this.notChannel);
}
}
UPDATE:
I tested the command adb shell dumpsys deviceidle force-idle
on the terminal to force idle state and Acc was still acquiring... so no idea why it stops after 3 minutes on my XIAOMI Pocophone F1 Android 10 (API 29). I don't know if the doze mode can be forced with any other command...