Android Oreo前台服务被杀死问题及保活诉求
Let's tackle the frustrating issue you're facing: your foreground location service getting killed when opening Settings/Camera on your Huawei MediaPad T5 running Android 8, even after applying common fixes like battery optimization exclusion and START_STICKY. I'll walk through the root causes and actionable fixes to keep your service running reliably, or ensure it restarts instantly if killed.
Key Root Causes in Your Current Code
Before diving into fixes, let's highlight the biggest flaws in your existing implementation that are leaving your service vulnerable:
- WakeLock is a local variable: You create and acquire the WakeLock inside
onCreate()as a temporary local variable, which gets garbage collected immediately. This means the WakeLock doesn't stay active, letting the system put your service to sleep. - Notification priority is too low: Your notification channel uses
IMPORTANCE_DEFAULT, which Android Oreo+ might deprioritize—this is why the system replaces it with the "App using battery" notification. - No proper cleanup or fallback restart: Your
onDestroy()doesn't clean up resources, andSTART_STICKYalone isn't reliable on Huawei's custom EMUI for instant restarts.
Actionable Fixes
1. Fix the WakeLock Implementation
Make the WakeLock a class-level member to keep it in memory, and release it properly when the service is destroyed:
public class LocationUpdatesService extends Service { // Add this as a class member to retain the lock private PowerManager.WakeLock mWakeLock; @Override public void onCreate() { // ... existing code ... PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE); mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "wl:location"); // Use timed acquire to avoid permanent lock (adjust duration as needed) mWakeLock.acquire(10 * 60 * 1000L); // ... existing code ... } @Override public void onDestroy() { super.onDestroy(); // Release WakeLock to avoid battery drain if (mWakeLock != null && mWakeLock.isHeld()) { mWakeLock.release(); } mServiceHandler.removeCallbacksAndMessages(null); // Clean up location updates to avoid leaks removeLocationUpdates(); } }
2. Boost Notification Priority & Avoid System Replacement
Huawei's system replaces low-priority foreground notifications. Update your channel to use IMPORTANCE_HIGH and mark the notification as a critical service:
private void createNotificationChannel() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { CharSequence name = getString(R.string.app_name); String description = "Real-time location tracking service"; NotificationChannel channel = new NotificationChannel(CHANNEL_ID, name, NotificationManager.IMPORTANCE_HIGH); channel.setDescription(description); channel.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC); channel.setSound(null, null); // Disable sound to avoid user annoyance mNotificationManager.createNotificationChannel(channel); } } // Update your getNotification() method to reinforce service priority private Notification getNotification() { // ... existing intent setup ... NotificationCompat.Builder builder = new NotificationCompat.Builder(this) // ... existing actions ... .setPriority(NotificationCompat.PRIORITY_HIGH) .setCategory(NotificationCompat.CATEGORY_SERVICE) // Mark as essential service .setSmallIcon(R.mipmap.ic_launcher) .setOngoing(true) // Prevent users from dismissing the notification // ... existing code ... return builder.build(); }
3. Bypass Huawei's Custom Battery Restrictions
Huawei's EMUI has aggressive battery optimization that ignores standard Android settings. Take these steps:
- Add and request battery optimization exemption permission:
Add this to yourAndroidManifest.xml:
Request user approval in your activity:<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { PowerManager pm = (PowerManager) getSystemService(POWER_SERVICE); if (!pm.isIgnoringBatteryOptimizations(getPackageName())) { Intent intent = new Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS); intent.setData(Uri.parse("package:" + getPackageName())); startActivity(intent); } } - Guide users to add your app to Huawei's Protected Apps:
On Huawei devices, go to Settings > Battery > Launch Manager > [Your App] > Set to "Manual management" and enable "Allow background activity", "Auto-launch", and "Run in background".
4. Add a Fallback Restart Mechanism
START_STICKY isn't reliable on Huawei. Use WorkManager to restart the service if it's killed:
- Add WorkManager dependency to your
build.gradle:implementation "androidx.work:work-runtime:2.8.1" - Create a Worker to restart your service:
public class RestartLocationServiceWorker extends Worker { public RestartLocationServiceWorker(@NonNull Context context, @NonNull WorkerParameters params) { super(context, params); } @NonNull @Override public Result doWork() { Intent intent = new Intent(getApplicationContext(), LocationUpdatesService.class); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { getApplicationContext().startForegroundService(intent); } else { getApplicationContext().startService(intent); } return Result.success(); } } - Schedule the worker in your service's
onDestroy():@Override public void onDestroy() { // ... existing cleanup code ... // Schedule periodic restart check PeriodicWorkRequest workRequest = new PeriodicWorkRequest.Builder(RestartLocationServiceWorker.class, 15, TimeUnit.MINUTES) .setConstraints(new Constraints.Builder() .setRequiredNetworkType(NetworkType.CONNECTED) .build()) .build(); WorkManager.getInstance(this).enqueue(workRequest); }
5. Optimize Location Request Frequency
Your current 1-second update interval is extremely battery-intensive, making the system more likely to kill your service. Adjust to a more reasonable interval (e.g., 5-10 seconds) unless you absolutely need 1-second precision:
private static final long UPDATE_INTERVAL_IN_MILLISECONDS = 5000; // 5 seconds private static final long FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS = UPDATE_INTERVAL_IN_MILLISECONDS / 2;
Additional Tips
- Remove Toast from background code: Your
SavetoServer()method callsToast.makeText(), which will crash when running in a background thread. Replace it with a log statement, or use aHandlerto post to the main thread if you need user feedback. - Test real-world scenarios: Avoid testing with
adb shell am force-stopsince it bypasses normal system kill logic. Instead, open camera/settings and monitor the service viaadb shell dumpsys activity services.
内容的提问来源于stack exchange,提问作者ali

