From 984a507ffad0cee3adb07f5c42c96bd9f8e70494 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Sat, 28 May 2016 00:01:39 +0200 Subject: [PATCH 1/3] fix random crash in WifiStateChangeService java.lang.NullPointerException: Attempt to invoke virtual method 'android.os.Parcelable android.content.Intent.getParcelableExtra(java.lang.String)' on a null object reference at org.fdroid.fdroid.net.WifiStateChangeService.onHandleIntent(WifiStateChangeService.java:56) at android.app.IntentService$ServiceHandler.handleMessage(IntentService.java:65) at android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:135) at android.os.HandlerThread.run(HandlerThread.java:61) fixes #559 --- .../java/org/fdroid/fdroid/net/WifiStateChangeService.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/src/main/java/org/fdroid/fdroid/net/WifiStateChangeService.java b/app/src/main/java/org/fdroid/fdroid/net/WifiStateChangeService.java index 3bf597d8f..84f132cf5 100644 --- a/app/src/main/java/org/fdroid/fdroid/net/WifiStateChangeService.java +++ b/app/src/main/java/org/fdroid/fdroid/net/WifiStateChangeService.java @@ -56,6 +56,10 @@ public class WifiStateChangeService extends IntentService { @Override protected void onHandleIntent(Intent intent) { android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_LOWEST); + if (intent == null) { + Utils.debugLog(TAG, "received null Intent, ignoring"); + return; + } Utils.debugLog(TAG, "WiFi change service started, clearing info about wifi state until we have figured it out again."); NetworkInfo ni = intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO); wifiManager = (WifiManager) getSystemService(WIFI_SERVICE); From 6166d9afc9d70384658068cc5f2f98249d62acfb Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Sat, 28 May 2016 00:35:40 +0200 Subject: [PATCH 2/3] fix random crash in WifiStateChangeService Some of these devices do shitty things. htc_europe HTC EVO 3D X515m java.lang.RuntimeException: An error occured while executing doInBackground() at android.os.AsyncTask$3.done(AsyncTask.java:278) at java.util.concurrent.FutureTask$Sync.innerSetException(FutureTask.java:273) at java.util.concurrent.FutureTask.setException(FutureTask.java:124) at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:307) at java.util.concurrent.FutureTask.run(FutureTask.java:137) at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:208) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569) at java.lang.Thread.run(Thread.java:864) Caused by: java.lang.NullPointerException at java.net.NetworkInterface.getNetworkInterfacesList(NetworkInterface.java:286) at java.net.NetworkInterface.getNetworkInterfaces(NetworkInterface.java:262) at org.fdroid.fdroid.net.WifiStateChangeService.setIpInfoFromNetworkInterface(WifiStateChangeService.java:202) at org.fdroid.fdroid.net.WifiStateChangeService.access$300(WifiStateChangeService.java:37) at org.fdroid.fdroid.net.WifiStateChangeService$WaitForWifiAsyncTask.doInBackground(WifiStateChangeService.java:99) at org.fdroid.fdroid.net.WifiStateChangeService$WaitForWifiAsyncTask.doInBackground(WifiStateChangeService.java:71) at android.os.AsyncTask$2.call(AsyncTask.java:264) at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305) ... 5 more java.lang.NullPointerException at java.net.NetworkInterface.getNetworkInterfacesList(NetworkInterface.java:286) at java.net.NetworkInterface.getNetworkInterfaces(NetworkInterface.java:262) at org.fdroid.fdroid.net.WifiStateChangeService.setIpInfoFromNetworkInterface(WifiStateChangeService.java:202) at org.fdroid.fdroid.net.WifiStateChangeService.access$300(WifiStateChangeService.java:37) at org.fdroid.fdroid.net.WifiStateChangeService$WaitForWifiAsyncTask.doInBackground(WifiStateChangeService.java:99) at org.fdroid.fdroid.net.WifiStateChangeService$WaitForWifiAsyncTask.doInBackground(WifiStateChangeService.java:71) at android.os.AsyncTask$2.call(AsyncTask.java:264) at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305) at java.util.concurrent.FutureTask.run(FutureTask.java:137) at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:208) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569) at java.lang.Thread.run(Thread.java:864) --- .../java/org/fdroid/fdroid/net/WifiStateChangeService.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/org/fdroid/fdroid/net/WifiStateChangeService.java b/app/src/main/java/org/fdroid/fdroid/net/WifiStateChangeService.java index 84f132cf5..69a41761d 100644 --- a/app/src/main/java/org/fdroid/fdroid/net/WifiStateChangeService.java +++ b/app/src/main/java/org/fdroid/fdroid/net/WifiStateChangeService.java @@ -192,7 +192,11 @@ public class WifiStateChangeService extends IntentService { private void setIpInfoFromNetworkInterface() { try { - for (Enumeration networkInterfaces = NetworkInterface.getNetworkInterfaces(); networkInterfaces.hasMoreElements();) { + Enumeration networkInterfaces = NetworkInterface.getNetworkInterfaces(); + if (networkInterfaces == null) { + return; + } + while (networkInterfaces.hasMoreElements()) { NetworkInterface netIf = networkInterfaces.nextElement(); for (Enumeration inetAddresses = netIf.getInetAddresses(); inetAddresses.hasMoreElements();) { From 7385d320b42af960be63c9c179e1cbf186c1398a Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Mon, 30 May 2016 12:05:19 +0200 Subject: [PATCH 3/3] fix crash when UpdateService receives null Intent IntentServices can get a null Intent if they are restarted after being killed. So this should be properly handled. "[The intent] may be null if the service is being restarted after its process has gone away, and it had previously returned anything except START_STICKY_COMPATIBILITY." https://developer.android.com/reference/android/app/IntentService.html#onStartCommand(android.content.Intent,%20int,%20int) ANDROID_VERSION=5.1.1 APP_VERSION_NAME=0.99.2 BRAND=samsung PHONE_MODEL=SM-G901F java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String android.content.Intent.getStringExtra(java.lang.String)' on a null object reference at org.fdroid.fdroid.UpdateService.onHandleIntent(UpdateService.java:342) at android.app.IntentService$ServiceHandler.handleMessage(IntentService.java:65) at android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:135) at android.os.HandlerThread.run(HandlerThread.java:61) --- .../org/fdroid/fdroid/CleanCacheService.java | 3 +++ .../java/org/fdroid/fdroid/UpdateService.java | 8 ++++-- .../fdroid/fdroid/net/DownloaderService.java | 25 +++++++++++++------ 3 files changed, 26 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/org/fdroid/fdroid/CleanCacheService.java b/app/src/main/java/org/fdroid/fdroid/CleanCacheService.java index 1f817f03e..cea679d9f 100644 --- a/app/src/main/java/org/fdroid/fdroid/CleanCacheService.java +++ b/app/src/main/java/org/fdroid/fdroid/CleanCacheService.java @@ -47,6 +47,9 @@ public class CleanCacheService extends IntentService { @Override protected void onHandleIntent(Intent intent) { + if (intent == null) { + return; + } Process.setThreadPriority(Process.THREAD_PRIORITY_LOWEST); Utils.clearOldFiles(Utils.getApkCacheDir(this), Preferences.get().getKeepCacheTime()); deleteStrayIndexFiles(); diff --git a/app/src/main/java/org/fdroid/fdroid/UpdateService.java b/app/src/main/java/org/fdroid/fdroid/UpdateService.java index bfe7f1ff8..be0565afa 100644 --- a/app/src/main/java/org/fdroid/fdroid/UpdateService.java +++ b/app/src/main/java/org/fdroid/fdroid/UpdateService.java @@ -313,8 +313,12 @@ public class UpdateService extends IntentService { Process.setThreadPriority(Process.THREAD_PRIORITY_LOWEST); final long startTime = System.currentTimeMillis(); - String address = intent.getStringExtra(EXTRA_ADDRESS); - boolean manualUpdate = intent.getBooleanExtra(EXTRA_MANUAL_UPDATE, false); + boolean manualUpdate = false; + String address = null; + if (intent != null) { + address = intent.getStringExtra(EXTRA_ADDRESS); + manualUpdate = intent.getBooleanExtra(EXTRA_MANUAL_UPDATE, false); + } try { // See if it's time to actually do anything yet... diff --git a/app/src/main/java/org/fdroid/fdroid/net/DownloaderService.java b/app/src/main/java/org/fdroid/fdroid/net/DownloaderService.java index 8dc833d29..d3e7e6e90 100644 --- a/app/src/main/java/org/fdroid/fdroid/net/DownloaderService.java +++ b/app/src/main/java/org/fdroid/fdroid/net/DownloaderService.java @@ -33,7 +33,6 @@ import android.os.Process; import android.support.v4.content.IntentCompat; import android.support.v4.content.LocalBroadcastManager; import android.text.TextUtils; -import android.util.Log; import org.fdroid.fdroid.ProgressListener; import org.fdroid.fdroid.Utils; @@ -46,9 +45,14 @@ import java.net.URL; /** * DownloaderService is a service that handles asynchronous download requests * (expressed as {@link Intent}s) on demand. Clients send download requests - * through {@link android.content.Context#startService(Intent)} calls; the - * service is started as needed, handles each Intent in turn using a worker - * thread, and stops itself when it runs out of work. + * through {@link #queue(Context, String)} calls. The + * service is started as needed, it handles each {@code Intent} using a worker + * thread, and stops itself when it runs out of work. Requests can be canceled + * using {@link #cancel(Context, String)}. If this service is killed during + * operation, it will receive the queued {@link #queue(Context, String)} and + * {@link #cancel(Context, String)} requests again due to + * {@link Service#START_REDELIVER_INTENT}. Bad requests will be ignored, + * including on restart after killing via {@link Service#START_NOT_STICKY}. *

* This "work queue processor" pattern is commonly used to offload tasks * from an application's main thread. The DownloaderService class exists to @@ -112,10 +116,15 @@ public class DownloaderService extends Service { @Override public int onStartCommand(Intent intent, int flags, int startId) { Utils.debugLog(TAG, "Received Intent for downloading: " + intent + " (with a startId of " + startId + ")"); + + if (intent == null) { + return START_NOT_STICKY; + } + String uriString = intent.getDataString(); if (uriString == null) { - Log.e(TAG, "Received Intent with no URI: " + intent); - return START_STICKY; + Utils.debugLog(TAG, "Received Intent with no URI: " + intent); + return START_NOT_STICKY; } if (ACTION_CANCEL.equals(intent.getAction())) { @@ -128,7 +137,7 @@ public class DownloaderService extends Service { } else if (isActive(uriString)) { downloader.cancelDownload(); } else { - Log.e(TAG, "ACTION_CANCEL called on something not queued or running (expected to find message with ID of " + whatToRemove + " in queue)."); + Utils.debugLog(TAG, "ACTION_CANCEL called on something not queued or running (expected to find message with ID of " + whatToRemove + " in queue)."); } } else if (ACTION_QUEUE.equals(intent.getAction())) { Message msg = serviceHandler.obtainMessage(); @@ -138,7 +147,7 @@ public class DownloaderService extends Service { serviceHandler.sendMessage(msg); Utils.debugLog(TAG, "Queued download of " + uriString); } else { - Log.e(TAG, "Received Intent with unknown action: " + intent); + Utils.debugLog(TAG, "Received Intent with unknown action: " + intent); } return START_REDELIVER_INTENT; // if killed before completion, retry Intent