I have an Android alarm clock app. I have the usual(?) alarm Intent -> receiver -> activity chain, whose last step creates a full-screen window and sounds the alarm.
All this works fine on pre-Oreo (API 26) versions of Android. But on Oreo, when the alarm fires, the System UI crashes and I get this exception in the emulator (slightly reformatted here):
12-12 01:15:02.864 9570-9570/com.android.systemui E/AndroidRuntime:
FATAL EXCEPTION: main
Process: com.android.systemui, PID: 9570
java.lang.NullPointerException: Attempt to invoke virtual method 'void com.android.systemui.statusbar.phone.NavigationBarFragment.onKeyguardOccludedChanged(boolean)' on a null object reference
at com.android.systemui.statusbar.phone.StatusBar.onKeyguardOccludedChanged(StatusBar.java:3843)
at com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager.setOccluded(StatusBarKeyguardViewManager.java:277)
at com.android.systemui.keyguard.KeyguardViewMediator.handleSetOccluded(KeyguardViewMediator.java:1176)
at com.android.systemui.keyguard.KeyguardViewMediator.-wrap14(Unknown Source:0)
at com.android.systemui.keyguard.KeyguardViewMediator$4.handleMessage(KeyguardViewMediator.java:1531)
at android.os.Handler.dispatchMessage(Handler.java:105)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6541)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)
As a possible clue, I've found that when I remove WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED from win.addFlags(), it doesn't crash -- but of course, it also doesn't show the alarm when the phone is locked.
I don't remember everything I've tried, but here are some of the things:
Locating Android's StatusBar.java source code to try to figure out exactly what thing is null that's not supposed to be. My Google-fu has failed me here, apparently.
Explicitly dismissing the keyguard with something like getSystemService(KeyguardManager.class).requestDismissKeyguard(this, null);.
Dismissing the keyguard by using WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD.
Both explicitly showing and explicitly hiding the status bar.
I think I tried some other method of showing the window when locked -- like, calling setShowWhenLocked(true) or something like that. But it didn't help, and anyway that method was added only in API 27, so it wouldn't solve the problem for API 26 even if it had worked.
Um ... other things I no longer remember.
None of these has had any effect.
Clearly this can work, because other alarm clock apps work under Oreo. What am I doing wrong?
Known bug that has been fixed it seems. Especially on the emulator.
So update the image used in the emulator.
It was present in the original Oreo release it seems according to the history if I interpret it correctly. Fixed in 8.0.0_r21 and later, present in 8.0.0_r17 and earlier and can't see any between those).
What exact versions of Oreo, have you tried 8.1 and/or various patch levels?
Because it's was fixed Sep 20 according to this commit, maybe another commit as well:
https://android.googlesource.com/platform/frameworks/base/+/8078996f4a8b1718a2ca56ff52fd1f4d522e7720%5E1..8078996f4a8b1718a2ca56ff52fd1f4d522e7720/
Possibly:
https://android.googlesource.com/platform/frameworks/base/+/9c4faa85f1bc4ffc2aa949da7b5d8439f4c638a2
Or their related source commit (noticed it was merge commits).
I quote one of them:
Fix random systemui crashes during boot
When trying to boot android in emulator, systemui may crash due to an
uninitialized value of mNavigationBar probably because of some race
condition during initialization caused by emulation performance issues
Related
I have a reminder app which needs to show reminders on time even if the phone is in Doze mode. This was appeared to be fine when compiling using the Android 7.1 SDK.
My BroadcastReceiver gets a WAKE_LOCK when it starts and releases it in a finally clause. It also logs activity to a local SQLLite database (for debug)
I've now changed to compile with Android 8.1 SDK and still all works fine
when the phone is not in Doze mode.
However, when the phone goes into Doze the App crashes at the due time of the alarm. My logging statement, which is the first line within OnReceive, is not invoked.
I have traps in for uncaught exceptions, which report to AppCenter and record locally. These work for other exceptions.
TaskScheduler.UnobservedTaskException += ReportUnobservedTaskException;
AppDomain.CurrentDomain.UnhandledException += ReportUnhandledException;
AndroidEnvironment.UnhandledExceptionRaiser += ReportThrowableEvent;
Can anybody advise why and where this might be failing, or how I can debug it better?
It feels like a change since moving the 8.1 SDK for compiling, but I can't see anything that has changed that would affect this.
Answering my own question in case it helps somebody else.
Investigation of the logcat shows that the problem here was that the application was not initialized when the Broadcast Receiver was invoked.
logcat showed the message:
android.runtime.JavaProxyThrowable: System.InvalidOperationException: You MUST call
Xamarin.Forms.Init(); prior to using it.
It appears that a scheduled job was crashing the app and so when the alarm fired the receiver was not initialized and could not deal with the message.
Next investigation is why the scheduled job failed ....
I'm getting a crash report on Firebase with the message
Calling startActivity() from outside of an Activity context requires
the FLAG_ACTIVITY_NEW_TASK flag.
This error occurs on a Samsung GT-I9500 with Android 19. I can't reproduce the error o my Google Pixel with Android Oreo (27).
I know how to set the flag, but I'm curious to know why this error occurs only on some versions of Android.
Here's how I'm starting the Activity:
context.getApplicationContext().startActivity(intent);
I'm curious to know why this error occurs only on some versions of Android.
Because of a bug. See this issue and this issue.
For the past few weeks, I have on my crash reporter:
Fatal Exception: java.lang.RuntimeException: Unable to start service com.####.MyService#ef705d8 with Intent { act=HIDE cmp=com.####/.MyService (has extras) }: java.lang.RuntimeException: android.os.DeadSystemException
at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:3344)
at android.app.ActivityThread.-wrap21(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1583)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6121)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:889)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:779)
This crash is present on:
all Samsung devices 7.0
all Nexus devices on 7.1.2
Note:
It is not due to a recent update of our application, just an OS updates on theses phones.
It is a very very frequent crashes (by far our biggest).
Our users don't report crashes than before (is this crash actually visible for the user?)
We are not able to reproduce it on our side
As you can see into the stack trace, the code impacted is system only. Not much I can do from my side to try and catch and handle the issue.
I checked the thread Android DeadSystemException but that doesn't help me much.
I know that DeadSystemException is:
The core Android system has died and is going through a runtime restart. All running apps will be promptly killed.
Is there anything we can do but to say "that's system, we cannot do anything"?
When the device is being restarted, you cannot run an app. Any app, not just yours but any given app cannot run when the device is restarting. AFAIK it occurs when you try to do something when the system crashes. Meaning if the system crashes and as it restarts your app starts a service or does something you get that error.
Meaning the exception is not connected to your app, but the Android OS and there is nothing you can do about it.
The crash being related to starting a service is because that is what your app did when the system crashed.
So: The error is something the system threw because your app did something when the system did a run-time reboot. There is nothing you can do about this, as you cannot control the Android OS from an app.
I've had the same issue. I implemented a service that uses the android SensorService. In some point of the time, two things happened but I still don't know which one caused the other. 1) The runtime restarted 2) The android SensorService died. I have implemented a default unhandled exceptions handler because I was debugging some other stuff on my app. I noticed that such handler, at least sometimes was catching that exception.
I followed this tutorial to implement it https://doandroid.wordpress.com/2011/11/19/writing-crash-reports-into-device-sd-card/
So, supposing that you implement this handler and it is actually being called when the system dies, you can add some sort of validations inside the handler such that if the exception is the DeadSystemException, you can set up an alarm to restart your application in let's say, 5 minutes or something.
This is of course not an ideal solution, but at least might be a workaround to your problem until you figure out what is really going on with the system.
Some information about how to restart you app programmatically:
Force application to restart on first activity
Your app crashed because of android OS system dies.
Here is the reference.
https://developer.android.com/reference/android/os/DeadSystemException
The core Android system has died and is going through a runtime restart. All running apps will be promptly killed.
I was wondering if it's possible for third-party apps to dynamically add permission to the system or not. According to this book, it is possible through the use of the public addPermission() API; however, I am getting a SecurityException that says "java.lang.SecurityException: You either need MANAGE_USERS or CREATE_USERS permission to: query users". I just wanted to make sure it is really because the system doesn't allow it and not because I messed up something in my code. If it is the case, dynamic addition of permissions is not allowed to third-party apps not signed with the system certificate, it would be great if somebody could explain the reasoning behind this choice.
Here is how I add the permission programmatically:
public void addDynamicPermission() {
PermissionInfo pi = new PermissionInfo();
pi.name = "com.somedomain.permission.MY_PERMISSION";
pi.labelRes = R.string.permission_label;
pi.protectionLevel = PermissionInfo.PROTECTION_DANGEROUS;
final PackageManager packageManager = getApplicationContext().getPackageManager();
packageManager.addPermission(pi);
}
This is what I have in my manifest file:
<permission-tree android:name="com.somedomain.permission" />
and this is the full java stack for the exception:
FATAL EXCEPTION: main
Process: com.example.myapp, PID: 11824
java.lang.SecurityException: You either need MANAGE_USERS or CREATE_USERS permission to: query users
at android.os.Parcel.readException(Parcel.java:1684)
at android.os.Parcel.readException(Parcel.java:1637)
at android.content.pm.IPackageManager$Stub$Proxy.addPermission(IPackageManager.java:2870)
at android.app.ApplicationPackageManager.addPermission(ApplicationPackageManager.java:535)
at com.example.myapp.MainActivity.addDynamicPermission(MainActivity.java:183)
at com.example.myapp.MainActivity$6.onClick(MainActivity.java:64)
at android.view.View.performClick(View.java:5637)
at android.view.View$PerformClick.run(View.java:22429)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6119)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)
Thanks a lot!
TL;DR: The book is outdated and versions of Android newer than Lollipop do indeed require MANAGE_USERS or CREATE_USERS, both of which have a protectionLevel of 3 (signatureOrSystem).
Longer answer:
A while back, in the KitKat era, I wrote some test code similar to yours and I recall it working fine. That was a few years ago. I just fired up that old app in my current Nougat (7.0) environment and ended up with the exact same exception that you are seeing. Curious, I reinstalled KitKat (4.4.4), Lollipop (5.1), and Marshmallow (6.0) instances and tried the app on each.
For 4.4.4 and 5.1, everything works fine. I verified this by running the code and then checking for the existence of the custom permission as follows:
% adb shell dumpsys package packagename | grep -i com.example
...
Permission [com.example.permission.TEST_PERMISSION] (79c4d6d):
sourcePackage=com.example.myapplication
perm=Permission{2c725da2 com.example.permission.TEST_PERMISSION}
...
However, on 6.0 and 7.0, I'm getting the security exception. A quick check of androidxref.com indicates that the exception is coming from either the getPrimaryUser or getUsers method in UserManagerService.
getPrimaryUsers doesn't exist in 4.4.4 or 5.1, and getUsers has always been protected with checkManageOrCreateUsersPermission. Therefore, I think its reasonable to assume that the addPermission chain was modified starting in 6.0 to get a list of users for some reason. So addPermission does not require MANAGE_USERS or CREATE_USERS, but a method it now calls does.
Whether or not this additional access control check is intended and the reasoning behind why, are questions I cannot answer.
I get Crash Analytics from Google for my Android app and I have been seeing this popup once in a while:
java.lang.NoClassDefFoundError
with regards to trying to open an Intent.
The scenario is, user clicks on button, they my code in the app is:
Intent intent = new Intent(nameOfCurrentActivity.this, nameOfNewActivity.class);
startActivity(intent);
Pretty straightforward stuff. It works fine on nearly all devices, including all the ones I own and have tested on. This new class being started isn't unique in that it requires any weird hardware (IE, not a camera activity), but it does access the internet via an Http request.
I have already researched the following links without gaining a hint towards a solution:
Why am I getting a NoClassDefFoundError in Java?
How to solve java.lang.NoClassDefFoundError?
My question is, how is it possible that this exception is being thrown on some devices (IE, a Samsung tablet), but not other devices? Shouldn't a new intent work on all devices if it works on one?
Thanks!
A lot of times this can be caused by classes running code that is dependent upon it being a certain API level, IE Marshmallow, but the device using it is on a previous API and the check for permissions is either ignored or not included; Like when you click disable inspection.
An example would be, say you are running something like a View.OnScrollChangeListener for a recyclerview. If you are coding and set it:
if(Build.VERSION.SDK_INT > Build.VERSION_CODES.M) {
myRecyclerview.setOnScrollChangeListener(this);
}
But don't include the build if check, it will throw the error. Another example would be if you are using the class itself as the context (this) for setting the scroll listener. If you use the class itself as the context for extending the Scroll listener but are on a device Pre-API 21, it will throw the error when the class loads. The error it throws is, as you probably guessed, NoClassDefError.
This happens because the Class mentioned in the 'future' API doesn't exist yet in the old phone and so it cannot find the class defined.
Check your code to see if anything in the class is requiring a certain API level to function and if it is, check to confirm you included the if checks for build version. Many times before I have disabled inspection because the red lines were bugging me and forgot to go back and add the checks.
I just wanted to add my own experience today. Apparently Supplier<T> exists in Java 8, however implementation of it and running it on Marshmallow generates NoClassDefFoundError. I was able to solve the problem by declaring custom MySupplier<T>. I tried to add as a comment but failed. Thanks for the explanation given by user7293284 above.