I am using a simple conditional check on Build.Version.SDK_INT in the onCreate method of my application (code below) to prevent strict mode being enabled on any Android OS earlier than 2.3. Up until recently this had been working fine, but after a re-jig of my project, I receive the following error:
Could not find class 'android.os.StrictMode$ThreadPolicy$Builder', referenced from method com.myPackage.MyApp.onCreate
I have heard that the way class dependencies were evaluated and loaded changed from a static analysis of the class to a 'lazy loading' system in Android 2.0, but since I am using 2.2, I don't think this is at play. I suspect there is something elsewhere in my project structure that is causing this error, but I am at a loss as to what that might be.
Has anyone here had a similar experience and could maybe shed some light on this? Any help would be gratefully received.
Thanks in advance for your help!
Please see my code below for reference:
public class MyApp extends Application {
#Override
public void onCreate() {
// Set up strict mode
int buildInt = Build.VERSION.SDK_INT;
Log.d(LogTags.TRIGGER_CODE, String.format("Build is %d (%s)", buildInt, Build.VERSION.CODENAME));
if (buildInt >= 9) {
StrictMode.setThreadPolicy(new ThreadPolicy.Builder()
.detectCustomSlowCalls()
.detectNetwork()
.build());
StrictMode.setVmPolicy((new VmPolicy.Builder()
.detectAll()
.build()));
}
super.onCreate();
}
}
This turned out to be just a symptom of another problem elsewhere in code, far too specific to the project to be worth going into here...
Thanks for the thoughts on the root cause here, and sorry for the 'doh' moment :)
Related
I am new in Android programming. I want to invoke a method in the class BatteryService by reflection. However, the following code fails above Android 5.0, including the newest Android 6.0.1, though it succeeds in Android 4.3. I have googled for days. But I cannot find any useful answers.
try{
Class myclass = Class.forName("com.android.server.BatteryService");
} catch (ClassNotFoundException e) {
e.printStackTrace();
Log.d("xx", "ClassNotFound!");
}
I have checked the source of Android 4.3, 5.0 and 6.0.1, and I am sure that the class BatteryService is in com.android.server. BTW, the modifier of BatteryService is public.
When running the above code, Android 5.0+ report an exception that the Class cannot be found. But the code works in Android 4.3. I wonder there are any new features introduced in Android 5.0 to preventing reflection?
Anyone knows the reason. Thanks a million!
As answered before, the classloader can't found the class. This is because the scope of the package is invisible if you don't have system's permissions (your apk should be installed in /system/app).
I recommend you to read this doc
You should avoid reflection and use the service class BatteryManager.
http://developer.android.com/reference/android/os/BatteryManager.html
Probably classloader doesn't know that class. App classloader and system classloader are not same.
EDITED
When starting systemserver, class path has set.
So, probably system app doesn't have this classloader.
https://android.googlesource.com/platform/frameworks/base.git/+/master/core/java/com/android/internal/os/ZygoteInit.java#461
/**
* Finish remaining work for the newly forked system server process.
*/
private static void handleSystemServerProcess(
ZygoteConnection.Arguments parsedArgs)
throws ZygoteInit.MethodAndArgsCaller {
....
ClassLoader cl = null;
if (systemServerClasspath != null) {
cl = new PathClassLoader(systemServerClasspath, ClassLoader.getSystemClassLoader());
Thread.currentThread().setContextClassLoader(cl);
}
/*
* Pass the remaining arguments to SystemServer.
*/
RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, cl);
I am very new to DexGuard and Proguard. I was going through their documentation and sample examples. They have dexguard_util which helps you detect if the application is tampered with and also helps in detecting if it is running in the environment it is supposed to run. The document suggests that this tamper and environment detection be encrypted using the following code is dexgaurd-project.txt.
-encryptclasses A$D
-encryptstrings A$D
follwing is the activity
public class A extends Activity
{
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
new D().c();
}
private class D
{
public void c()
{
//some code to which detects the tampering and environment and takes action accordingly
}
}
}
What if a hacker inject this line of code.
public class A extends Activity
{
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
//code commented by hacker
//new D().c();
}
private class D
{
public void c()
{
//some code to which detects the tampering and environment and takes action accordingly
}
}
}
Then my application will run without running those tests which I think is a big problem. Is my understanding of how reverse engineering works wrong or there are better ways of doing this. Please share better methods of doing this if they exist. Thanks in advance. Note that public class A cannot be encrypted as it is an entry point and is kept using this command in progaurd-project.txt
-keep class somepackage.A
When it comes to anti-tampering, it is important to keep in mind that their goal is not to stop any and all potential tampering efforts, but, rather, it's just a matter of raising the security bar of the target high enough to dissuade most attackers.
With that said, the
A bit of a tangent:
The document suggests that this tamper and environment detection be encrypted using the following code is dexgaurd-project.txt.
Class encryption does prevent basic static analysis of the application package, e.g. simply unzipping the package and loading it in jd-gui. However, as this answer shows, it's trivial to circumvent: one only has to hook into the static method that decrypts the apk on load, and dump it. But this allows the security bar to be raised.
Now back to your original question:
What if a hacker inject this line of code.
As an attacker, that would be the next step. However, that would require repackaging the app, and signing it with the hacker's signing key. Therefore, it is necessary to combine Dexguard's anti-tampering measures like checking the apk signature.
Is DexGuard tamper and Environment detection helpful?
In summary, yes, it is helpful in as far as it raises the bar above the vast majority of apps out there. But it's no silver bullet.
I have an app which uses Google Maps (v1) and from the crash reports, I am seeing this exception from time to time:
java.lang.NoClassDefFoundError: android.security.MessageDigest
at com.google.android.maps.KeyHelper.getSignatureFingerprint(KeyHelper.java:60)
at com.google.android.maps.MapActivity.createMap(MapActivity.java:513)
at com.google.android.maps.MapActivity.onCreate(MapActivity.java:409)
I have defined
<uses-library
android:name="com.google.android.maps"
android:required="true" />
inside the application tag and I am extending MapActivity as well. The application works fine on most devices but there are some uncommon ones that report this exception, usually on Android 4.0.4 like Woxter Tablet PC 90BL, TAB9008GBBK and other generic names.
From what I read in Stackoverflow, it is a problem in the ROM and it can be solved by the user doing some advanced tricks but what I want is to prevent this crash, as I don't think it can be solved, I just want to inform the user (and thell him to buy a better device :) and disable maps functionality instead of crashing. But I can't find a way to handle this error or test it with the devices I have.
Also my main activity is based on MapActivity so I don't know how can I handle this exception before opening it.
Disclaimer: I've not come across this error on any of my apps / devices but I solved a similar problem. May be that same technique can help you.
Given that the class is either unavailable or an exception occurrs while loading the class, why not try to force load it when your application starts ? Class.forName("android.security.MessageDigest") should load the class and you can catch the Error thrown from that call. I know its dirty, but it should work. You can declare a custom Application class on the manifest to make this check.
Class loading test
try
{
Class.forName("android.security.MessageDigest");
}
catch (Throwable e1)
{
e1.printStackTrace();
//Bad device
}
You can also perform a litmus test and check the functionality of the class should the class loading succeed by digesting a simple String.
Functional test
try
{
MessageDigest digester = MessageDigest.getInstance("MD5");
digester.update("test".getBytes("UTF-8"));
byte[] digest = digester.digest();
}
catch (Throwable e1)
{
e1.printStackTrace();
// Class available but not functional
}
If the class loading / litmus test fails, update a shared preference flag and let the user know that his device sucks :)
Try to change the import android.security.MessageDigest to java.security.MessageDigest
by the look at this link:
What is 'android.security.MessageDigest''?
It looks that the android.security.MessageDigest was remove from Honeycomb so change it to the java one. and check this link as well:
http://productforums.google.com/forum/#!category-topic/maps/google-maps-for-mobile/KinrGn9DcIE
As been suggested there by #XGouchet:
Try downloading the latest version of the Google Maps API and rebuild your application with targetSDK set to the highest available (as of today it should be 17 / Jelly Bean).
The class android.security.MessageDigest is an abstract class (see MessageDigest API) what means that it can't be instantiated right away. So what happens is, that any time a device/app can't find an implementation of this class you will get the exception above, namely
java.lang.NoClassDefFoundError: android.security.MessageDigest
It's a good question why this happens. May be some phone vendors didn't ship their phone with the required library that actually implements this abstract class. I faced a similar issue with the TUN.ko module in the past.
Approach 1
What should help is, if you provide your own (empty) implementation of this class that "implements" the abstract classes and methods like this:
public class MessageDigestSpi extends Object {
byte[] engineDigest() { return new byte[0]; }
void engineReset() { }
void engineUpdate(byte[] input, int offset, int len) { }
}
public class MessageDigest extends MessageDigestSpi {
}
... and put those classes into the folder <src>/java/security/. So this way you provide your own implementation that is always found and might contain some code in order to inform the user or provide an alternative implementation.
So the remaining questions are: what does the app do, if the implementation is provided by the system, too and how to control that the system implementation is the first choice?
The answer: which implementation is chosen depends on the import order. Looking at Eclipse you can define the order in the project properties, Java build path, tab order and export. Be sure that you have any system libraries on top that might include the system implementation (most likely the Android libraries). This way the system searches in those libraries first. If nothing is found your classes get loaded and executed.
Approach 2
As an alternative to the implementation in an own abstract class you could of course simply instantiate the MessageDigest class, catch the NoClassDefFoundError exception and store the result for later evaluation:
import android.security.MessageDigest;
public class MessageDigestTester {
private static Boolean messageDigestAvailable = null;
public static Boolean isLibraryAvailable() {
if (messageDigestAvailable == null) {
try {
MessageDigest digest = MessageDigest.getInstance("MD5");
messageDigestAvailable = true;
} catch (NoClassDefFoundError e) {
messageDigestAvailable = false;
}
}
return messageDigestAvailable;
}
}
Then use if (MessageDigestTester.isLibraryAvailable()) { } else { } in your code in order to encapsulate the usage of this library and to provide an alternative.
Approach two is easier to implement whereas approach one is the more sophisticated solution.
Hope this was helpful ... Cheers!
I need to implement Sentry for my android app, I try to find an example about how I have to implement this, but I can't find it.
I saw the Sentry documentation in http://sentry.readthedocs.org/en/latest/developer/client/index.html#server_name
But I have some questions.
If my app crash, the exception will be captured?
Should I put this code line into my try/catch?
var $resultId = myClient->captureException($myException); (in android code)
If somebody has a sample in android I will be grateful.
Thank you!
I am a little late but I just recently released a Sentry client for Android. It's in its early stages so feel free to pull request any changes that you see.
https://github.com/joshdholtz/Sentry-Android
public class MainActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Sentry will look for uncaught exceptions from previous runs and send them
Sentry.init(this, "YOUR-SENTRY-DSN");
}
}
Maybe try using something like BugSense? http://www.bugsense.com/
If it definitely has to be Sentry, then look at this example: https://stackoverflow.com/a/755151/349012
It shows you how to set your own uncaught exception handler so you can try and upload to Sentry.
I do have an old app that refuses to work on Android 4.1 devices. It's the NetworkOnMainThreadException that jumps in here.
So I tried to permit this with the following steps - but these don't work. I tested that with the 4.1 emulator. What is really needed to come around that error - app rewrite is no option. Currently I exclude 4.1 devices from my apps.
A class file ...
public class StrictModeWrapper {
static {
try {
Class.forName("android.os.StrictMode");
} catch (Exception exception) {
throw new RuntimeException(exception);
}
}
public static void checkAvailable() {
}
#SuppressLint("NewApi")
public static void setThreadPolicy() {
StrictMode.ThreadPolicy strictModeThreadPolicy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(strictModeThreadPolicy);
}
}
... called in an extended Application class:
public class MyApplication extends Application {
#Override
public void onCreate() {
super.onCreate();
try {
StrictModeWrapper.checkAvailable();
StrictModeWrapper.setThreadPolicy();
} catch (Throwable throwable) {
}
}
}
The extended Application class is registered in the Manifest and working.
Nothing seems to have changed in StrictMode since api 11. It must be the changes in some other android classes you used, that caused a StrictMode policy violation.
The Android documentation itself says
"But don't feel compelled to fix everything that StrictMode finds. "
But since its a NetworkOnMainThreadException you must do a thorough check. See all network communications in your app, and ensure that they are not blocking your main thread.
And make sure you remove/disable the StrictMode code in your release build, as it is only a developer tool to identify accidental mistakes.
Update:
Your app crashed because :
You had not blocked the execution of StrictMode policy setting code in your release build. It should be executed only while testing.
Something changed in the StrictMode class that caused the strict mode policy to reset after onCreate.
I have 2 questions :
Doesnt the crash indicate that the StrictMode policy was working? There was a policy violation and hence it crashed.
Doesnt it indicate that there is some network code in your app that blocks the main thread?
StrictMode behaves different on Android version >= 16 than prior releases. The docs suggest to issue StrictMode calls in onCreate() of an extended Application, Activity, etc.. At least onCreate() in an extended Application works different now and proofes the docs wrong (as of today).
Here's the StrictMode doc that describes how to add StrictMode calls to an extended application for example (that's wrong as of today):
StrictMode
Here's a Google Code issue that describes the problem and gives a workaround:
Google Code Issue 35298