In two projects that I've contributed I've had this Error:
FATAL EXCEPTION: main
java.lang.NoClassDefFoundError: java.util.Objects
That because I've implemented hashCode and equals methods using Objects class.
#Override
public int hashCode() {
int hash = 7;
hash = 97 * hash + Objects.hashCode(this.image);
hash = 97 * hash + Objects.hashCode(this.car);
return hash;
}
#Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final SummaryContent other = (SummaryContent) obj;
if (!Objects.equals(this.image, other.image)) {
return false;
}
return Objects.equals(this.car, other.car);
}
When I compile I don't get error or warnings. Why might it be happening?
I have the same problem in my new game. And i think, it happends, because different mobile manufacturer provide phones with different version of jvm.
My solution of this problem was copying implementation of methos equals from Objects to my project. It dirty, but work:
public static boolean equals(Object a, Object b) {
return (a == b) || (a != null && a.equals(b));
}
I was wrong. My device was android 4.1, which is api level 16 and the class Objects is since api level 19.
Related
I'm getting the following crash from renderscript on android:
100% of the crashes are on android 11 and 96% of the crashes are on Samsung devices. I removed all instances of renderscript, but this crash is still happening so maybe it's in one of my dependencies.
I found this got android.renderscript.RSRuntimeException on note4 which says that 4097 means a fatal driver error, but doesn't give any details on how to fix it.
Does anyone know how I can fix this crash?
UPDATE: when I search for "renderscript" in my app nothing comes up unless I put it on scope and then there's a bunch of references to it. I don't understand where they're coming from though
UPDATE: To be clear, I have removed all references to renderscript from my app but it seems like one or multiple of my dependencies are still using it. I need help isolating these dependencies. Something called android-30 is using renderscript. Is this the api 30 library or something? And then something called support/v8 is using renderscript. Is this the support library? (I do have support library enabled)
Migrate from RenderScript
RenderScript APIs are deprecated starting in Android 12. They will
continue to function, but we expect that device and component
manufacturers will stop providing hardware acceleration support over
time.
It seems to be a vendors issue (Driver issue)
Fatal error 4097: RS_ERROR_FATAL_UNKNOWN = 0x1000
static class MessageThread extends Thread {
RenderScript mRS;
boolean mRun = true;
int[] mAuxData = new int[2];
static final int RS_MESSAGE_TO_CLIENT_NONE = 0;
static final int RS_MESSAGE_TO_CLIENT_EXCEPTION = 1;
static final int RS_MESSAGE_TO_CLIENT_RESIZE = 2;
static final int RS_MESSAGE_TO_CLIENT_ERROR = 3;
static final int RS_MESSAGE_TO_CLIENT_USER = 4;
static final int RS_MESSAGE_TO_CLIENT_NEW_BUFFER = 5;
static final int RS_ERROR_FATAL_DEBUG = 0x0800;
static final int RS_ERROR_FATAL_UNKNOWN = 0x1000;
MessageThread(RenderScript rs) {
super("RSMessageThread");
mRS = rs;
}
public void run() {
// This function is a temporary solution. The final solution will
// used typed allocations where the message id is the type indicator.
int[] rbuf = new int[16];
mRS.nContextInitToClient(mRS.mContext);
while(mRun) {
rbuf[0] = 0;
int msg = mRS.nContextPeekMessage(mRS.mContext, mAuxData);
int size = mAuxData[1];
int subID = mAuxData[0];
if (msg == RS_MESSAGE_TO_CLIENT_USER) {
if ((size>>2) >= rbuf.length) {
rbuf = new int[(size + 3) >> 2];
}
if (mRS.nContextGetUserMessage(mRS.mContext, rbuf) !=
RS_MESSAGE_TO_CLIENT_USER) {
throw new RSDriverException("Error processing message from RenderScript.");
}
if(mRS.mMessageCallback != null) {
mRS.mMessageCallback.mData = rbuf;
mRS.mMessageCallback.mID = subID;
mRS.mMessageCallback.mLength = size;
mRS.mMessageCallback.run();
} else {
throw new RSInvalidStateException("Received a message from the script with no message handler installed.");
}
continue;
}
if (msg == RS_MESSAGE_TO_CLIENT_ERROR) {
String e = mRS.nContextGetErrorMessage(mRS.mContext);
// Throw RSRuntimeException under the following conditions:
//
// 1) It is an unknown fatal error.
// 2) It is a debug fatal error, and we are not in a
// debug context.
// 3) It is a debug fatal error, and we do not have an
// error callback.
if (subID >= RS_ERROR_FATAL_UNKNOWN ||
(subID >= RS_ERROR_FATAL_DEBUG &&
(mRS.mContextType != ContextType.DEBUG ||
mRS.mErrorCallback == null))) {
throw new RSRuntimeException("Fatal error " + subID + ", details: " + e);
}
if(mRS.mErrorCallback != null) {
mRS.mErrorCallback.mErrorMessage = e;
mRS.mErrorCallback.mErrorNum = subID;
mRS.mErrorCallback.run();
} else {
android.util.Log.e(LOG_TAG, "non fatal RS error, " + e);
// Do not throw here. In these cases, we do not have
// a fatal error.
}
continue;
}
if (msg == RS_MESSAGE_TO_CLIENT_NEW_BUFFER) {
if (mRS.nContextGetUserMessage(mRS.mContext, rbuf) !=
RS_MESSAGE_TO_CLIENT_NEW_BUFFER) {
throw new RSDriverException("Error processing message from RenderScript.");
}
long bufferID = ((long)rbuf[1] << 32L) + ((long)rbuf[0] & 0xffffffffL);
Allocation.sendBufferNotification(bufferID);
continue;
}
// 2: teardown.
// But we want to avoid starving other threads during
// teardown by yielding until the next line in the destructor
// can execute to set mRun = false
try {
sleep(1, 0);
} catch(InterruptedException e) {
}
}
//Log.d(LOG_TAG, "MessageThread exiting.");
}
}
I am trying to update an element in a dynamodb table but it never updates I've done some digging and found that in the updateItem function it doesn't think that the anything in the document has changed any adivice on how fix this (also I am able to get element no problem)
Document builder = table.getMemoById(Room);
builder.commit();
builder.put("room_status","clean");
Document tmp = table.curr_table.updateItem(builder,
new Primitive(Room),
new UpdateItemOperationConfig().withReturnValues(ReturnValue.UPDATED_NEW));
Log.d(TAG, tmp.toString());
after using the debugger I found that the issue is in Primitive.java where the last line and this.value is compared to this.value but needs to be other.value the file is read only any suggestion on how to fix this
public boolean equals(final Object obj) {
if (obj == null) {
return false;
}
if (obj == this) {
return true;
}
if (this.getClass() != obj.getClass()) {
return false;
}
final Primitive other = (Primitive) obj;
return Objects.equal(this.type, other.type) && Objects.equal(this.value, this.value);
}
turns out if you use the current version of the library 2.9.2 this is fixed I was using a much older version
Is there a way to programmatically configure an Android application to filter the log messages sent to logcat? I do understand, that logcat can be configured to filter out stuff, but I want to do the same inside the Android application.
Use case - I am actually using robolectric for my test cases, that I can run directly on my host machine and not on an emulator. This is actually extremely convenient for non-GUI stuff. Some of my code emits Android logs. I cannot attach logcat to see the output of that. I can redirect logs to regular stdout. But at this point I don't have filtering, so it's either grep or similar or sieving through thousands of lines of irrelevant stuff.
That's what I did:
public class CustomPrintStream extends PrintStream {
private String regexFilter;
private Pattern pattern;
public IonPrintStream(#NonNull File file) throws FileNotFoundException {
super(file);
}
public String getRegexFilter() {
return regexFilter;
}
public void setRegexFilter(String regexFilter) {
this.regexFilter = regexFilter;
if (regexFilter != null && !regexFilter.isEmpty()) {
pattern = Pattern.compile(regexFilter);
} else {
pattern = null;
}
}
#Override
public void println(String x) {
if (x != null && pattern != null && !pattern.matcher(x).find()) {
return;
}
System.out.println(x);
}
}
Usage on Robolectric (you can do it on your #Before method):
File file = new File("log.txt");
if (!file.exists() && !file.createNewFile()) {
throw new RuntimeException("Log file could not be created");
}
CustomPrintStream printStream = new CustomPrintStream(file);
printStream.setRegexFilter("[your regex here]");
ShadowLog.stream = printStream;
In your case, as you don't want to show some logs, you could filter something like this:
//I don't want to log CursorWindowStats and SQLiteCursor tags:
printStream.setRegexFilter("^((?!CursorWindowStats|SQLiteCursor).)*$");
I want to receive notification regarding crash report due to uncaught exception in my google analytics for my android app. I followed the steps given in https://developers.google.com/analytics/devguides/collection/android/v4/exceptions#parsing
but still I dont receive any crash report. I had a runtime exception when my app runs. I added the code for ga_reportUncaughtException as true:
true
in my analytics.xml. Is there anything else I need to add in order to get hit in google analytics account. Please help!
There is an open issue in Analytics. I'm experiencing the same behavior but on real devices from API 10 to 19.
https://code.google.com/p/analytics-issues/issues/detail?id=443
EDIT1: Removed question, just to answer the question described.
EDIT2: I tried to capture and send the exceptions using the Analytics ExceptionBuilder, but it didn't work.
It looks like the report is sent (at least LogCat is showing that the crash is reported), but it is not processed by Analytics.
While Google replies to the issue, I'm using this workaround. I guess it is not the best solution and the code can be improved, but it works for me:
I created a custom dimension in Analytics following this steps https://support.google.com/analytics/answer/2709829?hl=en
In my App, I created a custom exception handler, using the Analytics ExceptionReporter class. When an exception is caught, I get the stack trace and truncate it to 150 Bytes (Actually I'm getting only the first line of the stack and truncate it to 150 chars. I'm assuming that 1Char = 1 Byte). I have to truncate it, because it is the Max Lenght allowed by Analytics when sending custom dimensions values.
The stack trace is stored in a Shared Preference instead of being sent. I tried to send it directly, but it does not work once the App has crashed.
package com.company.package;
import java.lang.Thread.UncaughtExceptionHandler;
import android.content.Context;
import com.google.android.gms.analytics.ExceptionParser;
import com.google.android.gms.analytics.ExceptionReporter;
import com.google.android.gms.analytics.GoogleAnalytics;
import com.google.android.gms.analytics.HitBuilders;
import com.google.android.gms.analytics.Tracker;
public class GoogleAnalyticsTracker {
private static Tracker mTracker;
private static GoogleAnalytics mGa;
private Context mContext;
public GoogleAnalyticsTracker(Context context, int resource) {
mContext = context;
mGa = GoogleAnalytics.getInstance(context);
mTracker = getTracker(resource);
Thread.setDefaultUncaughtExceptionHandler(new AnalyticsExceptionReporter(mTracker,
Thread.getDefaultUncaughtExceptionHandler(), context));
}
synchronized Tracker getTracker(int xmlResource) {
return mGa.newTracker(xmlResource);
}
public void sendScreenLabel(String screenLabel) {
mTracker.setScreenName(screenLabel);
mTracker.send(new HitBuilders.AppViewBuilder().build());
}
public void sendCustomDimension(int index, String value) {
mTracker.send(new HitBuilders.AppViewBuilder().setCustomDimension(index, value).build());
}
private class AnalyticsExceptionReporter extends ExceptionReporter {
public AnalyticsExceptionReporter(Tracker tracker, UncaughtExceptionHandler originalHandler, Context context) {
super(tracker, originalHandler, context);
setExceptionParser(new AnalyticsExceptionParser());
}
#Override
public void uncaughtException(Thread t, Throwable e) {
String exceptionDescription = getExceptionParser().getDescription(t.getName(), e);
//Add code to store the exception stack trace in shared preferences
super.uncaughtException(t, e);
}
}
private class AnalyticsExceptionParser implements ExceptionParser {
#Override
public String getDescription(String arg0, Throwable arg1) {
StringBuilder exceptionFirsLine = new StringBuilder();
for (StackTraceElement element : arg1.getStackTrace()) {
exceptionFirsLine.append(element.toString());
break;
}
//150 Bytes is the maximum allowed by Analytics for custom dimensions values. Assumed that 1 Byte = 1 Character (UTF-8)
String exceptionDescription = exceptionFirsLine.toString();
if(exceptionDescription.length() > 150)
exceptionDescription = exceptionDescription.substring(0, 149);
return exceptionDescription;
}
}
}
In the MainActivity when OnStart(), I check if there is any stored stack trace in the shared preferences. If so, I send the custom dimension and clear the shared preference.
#Override
protected void onStart() {
super.onStart();
String exception = getExceptionFromSharedPreferences(this);
if(exception != null && !exception.isEmpty()) {
MainApplication.googleAnalyticsTracker.sendCustomDimension(1, exception);
}
clearExceptionFromSharedPreferences(this);
}
Finally I created a custom report in Analytics
EDIT 3:
I realized that I was sending only the fileName and lineNumber, but not the ExceptionName and the origin of the Exception in my package. I have improved the answer by adding code to also send that info.
private class AnalyticsExceptionParser implements ExceptionParser {
#Override
public String getDescription(String arg0, Throwable arg1) {
String exceptionDescription = getExceptionInfo(arg1, "", true) + getCauseExceptionInfo(arg1.getCause());
//150 Bytes is the maximum allowed by Analytics for custom dimensions values. Assumed that 1 Byte = 1 Character (UTF-8)
if(exceptionDescription.length() > 150)
exceptionDescription = exceptionDescription.substring(0, 150);
return exceptionDescription;
}
}
//#endregion
//#region PRIVATE METHODS
private String getCauseExceptionInfo(Throwable t) {
String causeDescription = "";
while(t != null && causeDescription.isEmpty()) {
causeDescription = getExceptionInfo(t, "com.myPackageName", false);
t = t.getCause();
}
return causeDescription;
}
private String getExceptionInfo(Throwable t, String packageName, boolean includeExceptionName) {
String exceptionName = "";
String fileName = "";
String lineNumber = "";
for (StackTraceElement element : t.getStackTrace()) {
String className = element.getClassName().toString().toLowerCase();
if(packageName.isEmpty() || (!packageName.isEmpty() && className.contains(packageName))){
exceptionName = includeExceptionName ? t.toString() : "";
fileName = element.getFileName();
lineNumber = String.valueOf(element.getLineNumber());
return exceptionName + "#" + fileName + ":" + lineNumber;
}
}
return "";
}
From my experience you need to understand two things about crashes and exceptions in Google Analytics:
1) Only basic information is stored - Google Analytics will only save the name of the exception and the location (Code file and line number) where the exception was thrown. No information beyond that will be accessible to you on GA. This is definitely not ideal and if you wish to track the actual content of your exceptions (mainly the call stack), use Google Play or implement your own solution.
2) Exceptions are not real-time. Exception information is collected and updated maybe once a day, so if you're experimenting with exceptions and you don't see them immediately, just give it time.
Google added a new ART runtime with Android 4.4. How can I determine whether ART or Dalvik is the current runtime?
Update
At least, as early as June 2014 Google has released an official documentation on how to correctly verify the current runtime in use:
You can verify which runtime is in use by calling System.getProperty("java.vm.version"). If ART is in use, the property's value is "2.0.0" or higher.
With that, now there is no need to go through reflection and simply check the corresponding system property:
private boolean getIsArtInUse() {
final String vmVersion = System.getProperty("java.vm.version");
return vmVersion != null && vmVersion.startsWith("2");
}
One possible way is to read the respective SystemProperty through reflection.
Sample:
package com.example.getcurrentruntimevalue;
import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class MainActivity extends Activity {
private static final String SELECT_RUNTIME_PROPERTY = "persist.sys.dalvik.vm.lib";
private static final String LIB_DALVIK = "libdvm.so";
private static final String LIB_ART = "libart.so";
private static final String LIB_ART_D = "libartd.so";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView tv = (TextView)findViewById(R.id.current_runtime_value);
tv.setText(getCurrentRuntimeValue());
}
private CharSequence getCurrentRuntimeValue() {
try {
Class<?> systemProperties = Class.forName("android.os.SystemProperties");
try {
Method get = systemProperties.getMethod("get",
String.class, String.class);
if (get == null) {
return "WTF?!";
}
try {
final String value = (String)get.invoke(
systemProperties, SELECT_RUNTIME_PROPERTY,
/* Assuming default is */"Dalvik");
if (LIB_DALVIK.equals(value)) {
return "Dalvik";
} else if (LIB_ART.equals(value)) {
return "ART";
} else if (LIB_ART_D.equals(value)) {
return "ART debug build";
}
return value;
} catch (IllegalAccessException e) {
return "IllegalAccessException";
} catch (IllegalArgumentException e) {
return "IllegalArgumentException";
} catch (InvocationTargetException e) {
return "InvocationTargetException";
}
} catch (NoSuchMethodException e) {
return "SystemProperties.get(String key, String def) method is not found";
}
} catch (ClassNotFoundException e) {
return "SystemProperties class is not found";
}
}
}
Hope this helps.
For anyone needing a JNI version:
#include <sys/system_properties.h>
static bool isArtEnabled() {
char buf[PROP_VALUE_MAX] = {};
__system_property_get("persist.sys.dalvik.vm.lib.2", buf);
// This allows libartd.so to be detected as well.
return strncmp("libart", buf, 6) == 0;
}
Or if you want to follow a code path closer to what shoe rat posted,
static bool isArtEnabled(JNIEnv *env)
{
// Per https://developer.android.com/guide/practices/verifying-apps-art.html
// if the result of System.getProperty("java.vm.version") starts with 2,
// ART is enabled.
jclass systemClass = env->FindClass("java/lang/System");
if (systemClass == NULL) {
LOGD("Could not find java.lang.System.");
return false;
}
jmethodID getProperty = env->GetStaticMethodID(systemClass,
"getProperty", "(Ljava/lang/String;)Ljava/lang/String;");
if (getProperty == NULL) {
LOGD("Could not find java.lang.System.getProperty(String).");
return false;
}
jstring propertyName = env->NewStringUTF("java.vm.version");
jstring jversion = (jstring)env->CallStaticObjectMethod(
systemClass, getProperty, propertyName);
if (jversion == NULL) {
LOGD("java.lang.System.getProperty('java.vm.version') did not return a value.");
return false;
}
const char *version = env->GetStringUTFChars(jversion, JNI_FALSE);
// Lets flip that check around to better bullet proof us.
// Consider any version which starts with "1." to be Dalvik,
// and all others to be ART.
bool isArtEnabled = !(strlen(version) < 2 ||
strncmp("1.", version, 2) == 0);
LOGD("Is ART enabled? %d (%s)", isArtEnabled, version);
env->ReleaseStringUTFChars(jversion, version);
return isArtEnabled;
}
The Android docs actually give the following suggestion:
You can verify which runtime is in use by calling System.getProperty("java.vm.version"). If ART is in use, the property's value is "2.0.0" or higher.
This seems accurate on my Nexus 4 w/ ART enabled (running Android 4.4.4). Nexus 5 on Dalvik returned 1.6.0.
A simple solution :
String vm = System.getProperty("java.vm.name") + " " + System.getProperty("java.vm.version");
On my Android 8.0 (API 26) phone, it returns Dalvik 2.1.0 .
I think you should be able to use System.getProperty with java.vm.name as the key.
In the JavaDoc its value is Dalvik, which let's hope it is Art or ART when using that runtime. It's worth a try...
final String vm = VMRuntime.getRuntime().vmLibrary();
and then compare vm with "libdvm.so" or "libart.so" to check if it is Dalvik or ART.
Reference: https://gitorious.org/cyandreamproject/android_frameworks_base/commit/4c3f1e9e30948113b47068152027676172743eb1