I find that there is an API dumpNativeHeap in android/os/Debug.java which has its implementation in native. How am i supposed to call this API? I tried calling as Debug.dumpNativeHeap(fd); but got an error saying the method does not exists.
dumpNativeHeap is not a public API. Use dumpHprofData instead.
As #segfault says, it's not part of the public API. However, if you're just wanting to use it for debugging, you can use reflection to access it. It's not recommended to do this in a production application, though.
try {
Method dumpNativeHeap = Debug.class.getDeclaredMethod("dumpNativeHeap", FileDescriptor.class);
dumpNativeHeap.setAccessible(true);
dumpNativeHeap.invoke(null, myFileDescriptor);
} catch (NoSuchMethodException e) {
// Shouldn't happen unless the method gets removed in a future API
}
Related
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 am trying to code an app that calls a method in android StatusBarManager. I did it the same way as the hack to expand the android status bar:
try {
Object service = getSystemService("statusbar");
Class<?> statusbarManager = Class.forName("android.app.StatusBarManager");
Method expand = statusbarManager.getMethod("disable", new Class[] { int.class });
expand.invoke(service, 0x00200000);
} catch (Exception e) {
e.printStackTrace();
System.out.println("DISABLE HOME ERROR");
}
Except the method I want to call is disable() instead of expand().
However, I am getting a security exception "neither and user nor the current process has permission android.permission.STATUS_BAR.
I tried adding it to the manifest but because it is a system apps permission, it only works if I copy my app to /system/app.
I messed around with RootTools http://code.google.com/p/roottools/ but couldn't figure out how to set the permissions. I tried setPermissions(0) and setUserPermissions("android.permissions.status_bar") but none works. I am not really sure how to use this library.
Any help would be greatly appreciated!
I am using 1.6 i.e. API 4 to build my application. There are couple of commands that are supported by higher versions. I want to write those commands and make application more compatible for higher versons. Like, I use Tabs. I want to use setLeftStripDrawable and setRightStripDrawable, but they are supported by API 8.
I write something like :
// I want these lines to come into affect only if the device SDK is greater than 7 as SDK of below 7, doesn't support these methods.
if (android.os.Build.VERSION.SDK_INT > 7) {
tw.setLeftStripDrawable(R.drawable.tab_selected_bar_left_v4); // TabWidget
}
EDIT : I want to set setLeftStripDrawable to the tabs used in my app. In my manifest I have uses-sdk android:minSdkVersion="4". If I write the lines as above and compile it in 2.3, it compiles successfully. When I run in 1.6 I get "java.lang.VerifyError". If I remove those liens and again run in 1.6, it works properly.
What should I do to execute those lines only if the device SDK api is > 7, and if it is less than that then those lines should not come under any affect ?
Any clue ?
if (Build.VERSION.SDK_INT > 7) {
...
}
I think you should use something like this. I did this by heart, so there might be some errors.
try {
Method twMethod = TabWidget.class.getMethod("setLeftStripDrawable", new Class[] { int.class });
twMethod.invoke(tw, R.drawable.yourdrawable);
} catch (NoSuchMethodException e) {
/* not supported */
} catch (IllegalArgumentException e) {
/* wrong class provided */
} catch (IllegalAccessException e) {
/* Java access control has denied access */
} catch (InvocationTargetException e) {
/* method has thrown an exception */
}
You can try looking at Android Reflection. I have not used it yet myself, but as far as i understand, you can test for classes and methods that you know the name of. Then you can instantiate and use them.
You can read some of the basics here: http://www.tutorialbin.com/tutorials/85977/java-for-android-developers-reflection-basics
Here's some sample Android code, using reflection, that does something similar. It calls the getRotation() method from the Display class; the method only exists in SDK 8+. I've used it in one of my apps and it works:
//I want to run this: displayrotation = getWindowManager().getDefaultDisplay().getRotation();
//but the getRotation() method only exists in SDK 8+, so I have to call it in a sly way, using Java "reflection"
try{
Method m = Display.class.getMethod("getRotation", (Class[]) null);//grab the getRotation() method if it exists
//second argument above is an array containing input Class types for the method. In this case it takes no inputs.
displayrotation = (Integer) m.invoke(getWindowManager().getDefaultDisplay(),(Object[]) null);
//again, second argument is an array of inputs, in this case empty
}catch(Exception e){//if method doesn't exist, take appropriate alternate actions
Log.w("getRotation","old OS version => Assuming 90 degrees rotation");
displayrotation = Surface.ROTATION_90;
}
I have released an app on the market with minSDK set to 4 (Android 1.6) but now I want to release an update with features unavailable in 1.6 so I need a higher minSDK.
So, my question is: Will users running 1.6 be notified of this update?...and if yes will they be able to download/install it?
No they shouldn't be notified of the update. The market will filter the application out all together and they will no longer be able to see it or receive updates.
If you want to add features that use a higher api level but not exclude user's of a lower api level you can use some reflection to enable this:
public static Method getExternalFilesDir;
try {
Class<?> partypes[] = new Class[1];
partypes[0] = String.class;
getExternalFilesDir = Context.class.getMethod("getExternalFilesDir", partypes);
} catch (NoSuchMethodException e) {
Log.e(TAG, "getExternalFilesDir isn't available in this devices api");
}
This piece of code is saying:
Within the Context.class have I got this method
getExternalFilesDir (API level 9)
If so instantiate the variable getExternalFilesDir as a reflective call to this method else leave it as null.
Then later on you can simply do
// If the user's device is API9 or above
if(getExternalFilesDir != null){
// Invoke is basically the same as doing Context.getExternalFilesDir(var1, var2);
getExternalFilesDir.invoke(variable1, variable2);
} else {
// User cannot use this method do something else
}
Hope that helps
on Android phones, under Call -> Additional settings -> Caller ID
it is possible to hide your caller ID. I want to do that programatically from my code, but was not able to find a way to do that.
I searched through
android.provider
android.telephony
for 2.1 release and was not able to find it.
Has anybody successfully solved this issue?
Thanks in advance. Best regards.
Here I will describe two approaches I tried.
1.) It is possible to display Additional Call Settings screen from your application. Although it looks like it is part of the Settings application, that is not true. This Activity is part of the Native Phone Application, and it may be approached with the following intent:
Intent additionalCallSettingsIntent = new Intent("android.intent.action.MAIN");
ComponentName distantActivity = new ComponentName("com.android.phone", "com.android.phone.GsmUmtsAdditionalCallOptions");
additionalCallSettingsIntent.setComponent(distantActivity);
startActivity(additionalCallSettingsIntent);
Then user has to manually press on the CallerID preference and gets radio button with 3 options.
This was not actually what I wanted to achieve when I asked this question. I wanted to avoid step where user has to select any further options.
2.) When approach described under 1.) is executed in the Native Phone Application, function setOutgoingCallerIdDisplay() from com.android.internal.telephony.Phone has been used.
This was the basis for the next approach: use Java Reflection on this class and try to invoke the function with appropriate parameters:
try
{
Class <?> phoneFactoryClass = Class.forName("com.android.internal.telephony.PhoneFactory");
try
{
Method getDefaultPhoneMethod = phoneFactoryClass.getDeclaredMethod("getDefaultPhone");
Method makeDefaultPhoneMethod = phoneFactoryClass.getMethod("makeDefaultPhone" , Context.class);
try
{
makeDefaultPhoneMethod.invoke(null, this);
Object defaultPhone = getDefaultPhoneMethod.invoke(null);
Class <?> phoneInterface = Class.forName("com.android.internal.telephony.Phone");
Method getPhoneServiceMethod = phoneInterface.getMethod("setOutgoingCallerIdDisplay", int.class, Message.class);
getPhoneServiceMethod.invoke(defaultPhone, 1, null);
}
catch (InvocationTargetException ex)
{
ex.printStackTrace();
}
catch (IllegalAccessException ex)
{
ex.printStackTrace();
}
}
catch (NoSuchMethodException ex)
{
ex.printStackTrace();
}
}
catch (ClassNotFoundException ex)
{
ex.printStackTrace();
}
Firstly I tried just to use getDefaultPhone(), but I get RuntimeException
"PhoneFactory.getDefaultPhone must be called from Looper thread"
Obviously, issue lies in the fact that I tried to call this method from the Message Loop that was not the Native Phone App one.
Tried to avoid this by making own default phone, but this was a security violation:
ERROR/AndroidRuntime(2338): java.lang.SecurityException: Permission Denial: not allowed to send broadcast android.provider.Telephony.SPN_STRINGS_UPDATED from pid=2338, uid=10048
The only way to overcome (both of) this would be to sign your app with the same key as the core systems app, as described under
Run secure API calls as root, android
I'm not sure if this is a global feature, but Australian phones can hide their number by prefixing the caller's number with #31# or 1831. This may not be the perfect solution, but a prefix like this could possibly work for your requirements during coding.