fix(logsender): run LogSenderService in foreground to avoid being killed by system (#1385)

This commit is contained in:
Akash Yadav
2023-12-20 22:24:41 +05:30
parent eb613d58a6
commit 3f15af6a7c
7 changed files with 155 additions and 4 deletions
+4
View File
@@ -27,6 +27,10 @@ android {
defaultConfig {
minSdk = 16
vectorDrawables {
useSupportLibrary = true
}
}
compileOptions {
+1
View File
@@ -23,6 +23,7 @@
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="com.itsaky.androidide.permission.BIND_LOG_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<application>
<provider
@@ -17,8 +17,18 @@
package com.itsaky.androidide.logsender;
import android.app.Notification;
import android.app.Notification.BigTextStyle;
import android.app.Notification.Builder;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.content.res.Resources;
import android.os.Build;
import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
import android.os.IBinder;
import android.widget.Toast;
import com.itsaky.androidide.logsender.utils.Logger;
@@ -31,32 +41,75 @@ import com.itsaky.androidide.logsender.utils.Logger;
public class LogSenderService extends Service {
private final LogSender logSender = new LogSender();
private static final int NOTIFICATION_ID = 644;
private static final String NOTIFICATION_CHANNEL_NAME = "LogSender Service";
private static final String NOTIFICATION_TITLE = "LogSender Service";
private static final String NOTIFICATION_TEXT = "Connected to AndroidIDE";
private static final String NOTIFICATION_CHANNEL_ID = "ide.logsender.service";
public static final String ACTION_START_SERVICE = "ide.logsender.service.start";
public static final String ACTION_STOP_SERVICE = "ide.logsender.service.stop";
@Override
public void onCreate() {
Logger.LOG.logThis();
super.onCreate();
setupNotificationChannel();
startForeground(NOTIFICATION_ID, buildNotification());
}
@Override
public IBinder onBind(Intent intent) {
Logger.debug("Unexpected request to bind.", intent);
return null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Logger.debug("onStartCommand", intent, flags, startId);
switch (intent.getAction()) {
case ACTION_START_SERVICE:
actionStartService();
break;
case ACTION_STOP_SERVICE:
actionStopService();
break;
default:
Logger.error("Unknown service action:", intent.getAction());
break;
}
return START_NOT_STICKY;
}
private void actionStartService() {
Logger.info("Starting log sender service...");
boolean result = false;
try {
result = logSender.bind(getApplicationContext());
Logger.debug("Bind to AndroidIDE:", result);
} catch (Exception err) {
Logger.error(getString(R.string.msg_bind_service_failed), err);
}
if (!result) {
Toast.makeText(this, getString(R.string.msg_bind_service_failed), Toast.LENGTH_SHORT).show();
stopSelf();
actionStopService();
}
}
return START_NOT_STICKY;
private void actionStopService() {
Logger.info("Stopping log sender service...");
stopSelf();
}
@Override
public void onTaskRemoved(Intent rootIntent) {
Logger.LOG.logThis();
if (!logSender.isConnected() && !logSender.isBinding()) {
Logger.debug("Not bound to AndroidIDE. Ignored.");
return;
}
@@ -67,7 +120,9 @@ public class LogSenderService extends Service {
@Override
public void onDestroy() {
Logger.LOG.logThis();
if (!logSender.isConnected() && !logSender.isBinding()) {
Logger.debug("Not bound to AndroidIDE. Ignored.");
return;
}
@@ -75,4 +130,61 @@ public class LogSenderService extends Service {
logSender.destroy(getApplicationContext());
super.onDestroy();
}
private void setupNotificationChannel() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
return;
}
NotificationChannel channel = new NotificationChannel(
NOTIFICATION_CHANNEL_ID,
NOTIFICATION_CHANNEL_NAME,
NotificationManager.IMPORTANCE_LOW
);
NotificationManager notificationManager = getSystemService(NotificationManager.class);
if (notificationManager != null) {
notificationManager.createNotificationChannel(channel);
}
}
private Notification buildNotification() {
Resources res = getResources();
// Set notification priority
// If holding a wake or wifi lock consider the notification of high priority since it's using power,
// otherwise use a low priority
int priority = Notification.PRIORITY_LOW;
// Build the notification
final Builder builder = new Builder(this);
builder.setContentTitle(NOTIFICATION_TITLE);
builder.setContentText(NOTIFICATION_TEXT);
builder.setStyle(new BigTextStyle().bigText(NOTIFICATION_TEXT));
builder.setPriority(priority);
if (VERSION.SDK_INT >= VERSION_CODES.O) {
builder.setChannelId(NOTIFICATION_CHANNEL_ID);
}
if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN_MR1) {
builder.setShowWhen(false);
}
builder.setSmallIcon(R.drawable.ic_androidide_log);
if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
builder.setColor(0xFF607D8B);
}
builder.setOngoing(true);
// Set Exit button action
Intent exitIntent = new Intent(this, LogSenderService.class).setAction(ACTION_STOP_SERVICE);
builder.addAction(android.R.drawable.ic_delete,
res.getString(R.string.notification_action_exit),
PendingIntent.getService(this, 0, exitIntent, PendingIntent.FLAG_IMMUTABLE));
return builder.build();
}
}
@@ -26,6 +26,7 @@ import android.content.ContentValues;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
import com.itsaky.androidide.logsender.LogSender;
@@ -54,7 +55,13 @@ public class LogSenderInstaller extends ContentProvider {
try {
final Intent intent = new Intent(application, LogSenderService.class);
application.startService(intent);
intent.setAction(LogSenderService.ACTION_START_SERVICE);
if (VERSION.SDK_INT >= VERSION_CODES.O) {
application.startForegroundService(intent);
} else {
application.startService(intent);
}
} catch (Exception e) {
// starting a background service is not allowed on Android 12+
@@ -25,7 +25,7 @@ import com.itsaky.androidide.utils.ILogger;
* @author Akash Yadav
*/
public class Logger {
private static final ILogger LOG = ILogger.newInstance("LogSender");
public static final ILogger LOG = ILogger.newInstance("LogSender");
public static void error(Object... messages) {
LOG.error(messages);
File diff suppressed because one or more lines are too long
@@ -17,4 +17,5 @@
<resources>
<string name="msg_bind_service_failed">Failed to bind to AndroidIDE</string>
<string name="notification_action_exit">Exit</string>
</resources>