-
Notifications
You must be signed in to change notification settings - Fork 131
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add support for restarting a Service.
- Loading branch information
jobhh
committed
Mar 1, 2024
1 parent
de73594
commit a3ecf29
Showing
9 changed files
with
280 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
54 changes: 54 additions & 0 deletions
54
process-phoenix/src/main/java/com/jakewharton/processphoenix/PhoenixService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
package com.jakewharton.processphoenix; | ||
|
||
import android.app.IntentService; | ||
import android.content.Intent; | ||
import android.os.Build; | ||
import android.os.Process; | ||
import android.os.StrictMode; | ||
|
||
/** | ||
* Please note that restarting a Service multiple times can result in an increasingly long delay between restart times. | ||
* This is a safety mechanism, since Android registers the restart of this service as a crashed service. | ||
* <p> | ||
* The observed delay periods are: 1s, 4s, 16s, 64s, 256s, 1024s. (on an Android 11 device) | ||
* Which seems to follow this pattern: 4^x, with x being the restart attempt minus 1. | ||
*/ | ||
public class PhoenixService extends IntentService { | ||
|
||
public PhoenixService() { | ||
super("PhoenixService"); | ||
} | ||
|
||
@Override | ||
protected void onHandleIntent(Intent intent) { | ||
if (intent == null) { | ||
return; | ||
} | ||
|
||
Process.killProcess(intent.getIntExtra(ProcessPhoenix.KEY_MAIN_PROCESS_PID, -1)); // Kill original main process | ||
|
||
Intent nextIntent; | ||
if (Build.VERSION.SDK_INT >= 33) { | ||
nextIntent = intent.getParcelableExtra(ProcessPhoenix.KEY_RESTART_INTENT, Intent.class); | ||
} else { | ||
nextIntent = intent.getParcelableExtra(ProcessPhoenix.KEY_RESTART_INTENT); | ||
} | ||
|
||
if (Build.VERSION.SDK_INT > 31) { | ||
// Disable strict mode complaining about out-of-process intents. Normally you save and restore | ||
// the original policy, but this process will die almost immediately after the offending call. | ||
StrictMode.setVmPolicy( | ||
new StrictMode.VmPolicy.Builder(StrictMode.getVmPolicy()) | ||
.permitUnsafeIntentLaunch() | ||
.build()); | ||
} | ||
|
||
if (Build.VERSION.SDK_INT >= 26) { | ||
startForegroundService(nextIntent); | ||
} else { | ||
startService(nextIntent); | ||
} | ||
|
||
Runtime.getRuntime().exit(0); // Kill kill kill! | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
52 changes: 52 additions & 0 deletions
52
sample/src/main/java/com/jakewharton/processphoenix/sample/NotificationBuilder.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
package com.jakewharton.processphoenix.sample; | ||
|
||
import android.Manifest; | ||
import android.annotation.TargetApi; | ||
import android.app.Notification; | ||
import android.app.NotificationChannel; | ||
import android.app.NotificationManager; | ||
import android.content.Context; | ||
import android.content.pm.PackageManager; | ||
import android.os.Build; | ||
import android.util.Log; | ||
|
||
public class NotificationBuilder { | ||
|
||
/** | ||
* Create a Notification, required to support Service restarting on Android 8 and newer | ||
*/ | ||
@TargetApi(26) | ||
public static Notification createNotification(Context context) { | ||
// Android 13 or higher requires a permission to post Notifications | ||
if (Build.VERSION.SDK_INT >= 33) { | ||
if (context.checkCallingOrSelfPermission(Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) { | ||
Log.e( | ||
"ProcessPhoenix", | ||
"Required POST_NOTIFICATIONS permission was not granted, cannot restart Service" | ||
); | ||
return null; | ||
} | ||
} | ||
|
||
// Android 8 or higher requires a Notification Channel | ||
if (Build.VERSION.SDK_INT >= 26) { | ||
// Creating an existing notification channel with its original values performs no operation, so it's safe to call this code multiple times | ||
NotificationChannel channel = new NotificationChannel( | ||
"ProcessPhoenix", | ||
"ProcessPhoenix", | ||
NotificationManager.IMPORTANCE_NONE | ||
); | ||
|
||
// Create Notification Channel | ||
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); | ||
notificationManager.createNotificationChannel(channel); | ||
} | ||
|
||
// Create a Notification | ||
return new Notification.Builder(context, "ProcessPhoenix") | ||
.setSmallIcon(android.R.mipmap.sym_def_app_icon) | ||
.setContentTitle("ProcessPhoenix") | ||
.setContentText("PhoenixService") | ||
.build(); | ||
} | ||
} |
54 changes: 54 additions & 0 deletions
54
sample/src/main/java/com/jakewharton/processphoenix/sample/RestartService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
package com.jakewharton.processphoenix.sample; | ||
|
||
import android.annotation.SuppressLint; | ||
import android.app.IntentService; | ||
import android.content.Intent; | ||
import android.os.Build; | ||
import android.os.Process; | ||
import android.util.Log; | ||
import com.jakewharton.processphoenix.ProcessPhoenix; | ||
|
||
import java.util.concurrent.ExecutorService; | ||
import java.util.concurrent.Executors; | ||
|
||
/** | ||
* This example service will attempt to restart after 1 second | ||
* <p> | ||
* Please note that restarting a Service multiple times can result in an increasingly long delay between restart times. | ||
* This is a safety mechanism, since Android registers the restart of this service as a crashed service. | ||
* <p> | ||
* The observed delay periods are: 1s, 4s, 16s, 64s, 256s, 1024s. (on an Android 11 device) | ||
* Which seems to follow this pattern: 4^x, with x being the restart attempt minus 1. | ||
*/ | ||
public class RestartService extends IntentService { | ||
|
||
public RestartService() { | ||
super("RestartService"); | ||
} | ||
|
||
@SuppressLint("ForegroundServiceType") | ||
@Override | ||
protected void onHandleIntent(Intent intent) { | ||
// Log something to console to easily track successful restarts | ||
Log.d( | ||
"ProcessPhoenix", | ||
"--- RestartService started with PID: " + Process.myPid() + " ---" | ||
); | ||
|
||
if (Build.VERSION.SDK_INT >= 26) { | ||
startForeground(1337, NotificationBuilder.createNotification(RestartService.this)); | ||
} | ||
|
||
// Trigger rebirth from a separate thread, such that the onStartCommand can finish properly | ||
ExecutorService executorService = Executors.newSingleThreadExecutor(); | ||
executorService.execute(() -> { | ||
try { | ||
Thread.sleep(1000); | ||
} catch (InterruptedException e) { | ||
// Ignore | ||
} | ||
ProcessPhoenix.triggerRebirth(RestartService.this, RestartService.class); | ||
// ProcessPhoenix.triggerRebirth(RestartService.this, new Intent(RestartService.this, RestartService.class)); | ||
}); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters