I just tested out proguard to obfuscate my android app.
But decompiling the apk shows that obfuscated functions have a weird annotation on top of them that displays the real function name, the real class name AND the real file name. How is that possible? Why is this happening?
The decompiled code looks like this,
#f(c = "com.my.app.package.Classname", f = "Classname.kt", l = {49, 51}, m = "RealFunctionName")
public static final class b extends i.b0.j.a.d {
public /* synthetic */ Object s;
public int t;
public final /* synthetic */ Classname u;
public Object v;
public Object w;
public Object x;
/* JADX INFO: super call moved to the top of the method (can break code semantics) */
public b(Classname classname, i.b0.d dVar) {
super(dVar);
this.u = classname;
}
#Override // i.b0.j.a.a
public final Object l(Object obj) {
this.s = obj;
this.t |= Integer.MIN_VALUE;
return this.u.c(this);
}
}
This happens even if I remove ALL proguard rules to make it obfuscate everything without any exceptions. So where does this annotation come from? And why does it happen? Any help would be appreciated!
Related
I'm trying to create a Lint rule in my Android code that checks the number if injections in a constructor, so if I exceed a certain number for a view model, for example, I will raise a lint warning.
I know that I have to implement a UastScanner in my Lint Detector, but I am getting lost because I cannot find good documentation. Has someone else ever done something like this? Or where can I find good deocumentation about it?
Thanks!
* NOTE - Read entire answer for edited solution. *
I was able to write the UAST conversion like so:
public class NumberOfDependenciesInjectedDetector extends Detector implements Detector.UastScanner {
private static final int NUMBER_OF_INJECTIONS_ALLOWED = 5;
private static final Class<? extends Detector> DETECTOR = NumberOfDependenciesInjectedDetector.class;
private static final EnumSet<Scope> SCOPE = Scope.JAVA_FILE_SCOPE;
private static final Implementation IMPLEMENTATION = new Implementation(DETECTOR, SCOPE);
public static final Issue ISSUE = Issue.create(
"NumberOfDependenciesInjected",
"Limit number of injections in a class via constructor",
"A longer description here",
Category.CORRECTNESS,
10,
Severity.ERROR,
IMPLEMENTATION
);
#Override
public List<Class<? extends UElement>> getApplicableUastTypes() {
return Collections.<Class<? extends UElement>>singletonList(UClass.class);
}
#Override
public UElementHandler createUastHandler(JavaContext context) {
return new ConstructorVisitor(context);
}
private static class ConstructorVisitor extends UElementHandler {
private JavaContext javaContext;
private ConstructorVisitor(JavaContext javaContext) {
this.javaContext = javaContext;
}
#Override
public void visitClass(UClass clazz){
UMethod[] methods = clazz.getMethods();
for(UMethod method : methods){
if(!method.isConstructor()) continue;
if (method.getParameterList().getParametersCount() > NUMBER_OF_INJECTIONS_ALLOWED) {
javaContext.report(ISSUE, method, javaContext.getLocation(method), "Injections exceed allowed value of " + NUMBER_OF_INJECTIONS_ALLOWED);
}
}
}
}
}
However, it seems that this still doesn't pick up Kotlin source files... very confusing.
EDIT: 12/19/17 - FIXED
The problem was two-fold:
1) There was indeed a hidden usage of a Psi method that was blocking the check from working. The visitClass method should not use getParameterList() but instead, getUastParameters(). Replace visitclass above with:
#Override
public void visitClass(UClass clazz){
UMethod[] methods = clazz.getMethods();
for(UMethod method : methods){
if(!method.isConstructor()) continue;
if (method.getUastParameters().size() > NUMBER_OF_INJECTIONS_ALLOWED) {
javaContext.report(ISSUE, clazz, javaContext.getLocation(method), "Injections exceed allowed value of " + NUMBER_OF_INJECTIONS_ALLOWED);
}
}
}
2) After speaking with Tor Norbye directly on the lint-dev group, he pointed out that Android Studio 3.0 in fact lint does not work externally with kotlin and therefore was not expected to work as described here. Upgrading to Android Studio 3.1 Canary and running the linter produced the expected report.
So I was able to find a solution using JavaScanner, but I haven't found anything yet using UastScanner (which it is what I want to use, since we have Kotlin classes too):
public class NumberOfDependenciesInjectedDetector extends Detector implements Detector.JavaScanner {
private static final int NUMBER_OF_INJECTIONS_ALLOWED = 5;
private static final Class<? extends Detector> DETECTOR = NumberOfDependenciesInjectedDetector.class;
private static final EnumSet<Scope> SCOPE = Scope.JAVA_FILE_SCOPE;
private static final Implementation IMPLEMENTATION = new Implementation(DETECTOR, SCOPE);
public static final Issue ISSUE = Issue.create(
"NumberOfDependenciesInjected",
"Limit number of injections in a class via constructor",
"A longer description here",
Category.CORRECTNESS,
10,
Severity.ERROR,
IMPLEMENTATION
);
#Override
public boolean appliesTo(Context context, File file) {
return true;
}
#Override
public Speed getSpeed(Issue issue) {
return Speed.FAST;
}
#Override
public List<Class<? extends Node>> getApplicableNodeTypes() {
return Collections.<Class<? extends Node>>singletonList(ConstructorDeclaration.class);
}
#Override
public AstVisitor createJavaVisitor(JavaContext context) {
return new ConstructorVisitor(context);
}
private static class ConstructorVisitor extends ForwardingAstVisitor {
private JavaContext javaContext;
private ConstructorVisitor(JavaContext javaContext) {
this.javaContext = javaContext;
}
#Override
public boolean visitConstructorDeclaration(ConstructorDeclaration node) {
if (node.astParameters().size() > NUMBER_OF_INJECTIONS_ALLOWED) {
javaContext.report(ISSUE, node, javaContext.getLocation(node), "My message goes here");
return true;
}
return false;
}
}
}
I am relatively new to StackOverflow and Android Studio so apologies for newbie question!
I recently switched over to Android Studio from Eclipse.
I am noticing that when one function in one of my source files has an error that ALL functions in that file on the project view pane on the top left are showing the red squiggly so it is a little more time consuming to actually get to the error. Any ideas as to why this is happening?
Thank you
As Shlublu points out, it is difficult to say without an example. Here is one possible situation. Take this class:
public class MyClass {
private int myNumber;
public MyClass( int number) {
this.myNumber = number;
}
public int getAnswer() {
return this.myNumber;
}
private void someMethod() {
int x = 0;
} // remove this } and all below is an error
#Override
public String toString() {
return String.valueOf(this.myNumber);
}
#Override
public boolean equals(Object obj) {
return true;
}
}
Removing the } at the end of the someMethod() causes all methods below that to have an error.
I have been implemented this project: https://github.com/yaylas/AndroidFaceRecognizer into Android Studio. I included OpenCV using tutorial: https://www.youtube.com/watch?v=OTw_GIQNbD8 (this is static initialization). Moreover, I set in Android Studio settings proper NDK location.
Problem is that, if I add this Class:
package com.yaylas.sytech.facerecognizer;
import java.util.Vector;
import org.opencv.core.Mat;
import org.opencv.core.MatOfRect;
import android.widget.Toast;
public class DetectionBasedTracker
{
public DetectionBasedTracker(String cascadeName, int minFaceSize, boolean isFaceDetector) {
mNativeObj = nativeCreateObject(cascadeName, minFaceSize, isFaceDetector);
}
public long getNativeObj(){
return mNativeObj;
}
public void setMinFaceSize(int size) {
nativeSetFaceSize(mNativeObj, size);
}
public void detect(Mat imageGray, MatOfRect faces) {
nativeDetect(mNativeObj, imageGray.getNativeObjAddr(), faces.getNativeObjAddr());
}
public void release() {
nativeDestroyObject(mNativeObj);
mNativeObj = 0;
}
public static Vector<Mat> imageVector = new Vector<Mat>();
public static void addElement(Mat m){
imageVector.add(m);
System.out.println("--------------------------------- elementAdded: "+imageVector.size());
}
public static long getElementAt(int index){
if(index >= imageVector.size() || index < 0){
return 0;
}
System.out.println("-------------------------***** get element: "+imageVector.size()+" index: "+index);
return imageVector.elementAt(index).getNativeObjAddr();
}
public static int getImageCount(){
return imageVector.size();
}
private long mNativeObj = 0;
private static native long nativeCreateObject(String cascadeName, int minFaceSize, boolean faceDetection);
private static native void nativeDestroyObject(long thiz);
private static native void nativeStart(long thiz);
private static native void nativeStop(long thiz);
private static native void nativeSetFaceSize(long thiz, int size);
private static native void nativeDetect(long thiz, long inputImage, long faces);
}
An error is returned:
Cannot resolve corresponding JNI function
I tried everything, but the error still is there. I would like to ask, where can be a problem?
There are several reasons why the runtime might not be able to resolve the JNI function. Test these hypotheses:
The native code library didn't get bundled into your APK. Look inside the APK for it.
The native code library is in the wrong directory of the APK. Again, look and see.
The Java class got mangled by ProGuard so the names no longer match with the native library. Try turning off ProGuard. It should be off for debug builds.
If your native code library is compiled for ARM but you're running in an x86 based Android emulator (or vice versa), it won't be able to load that library.
Think of more hypotheses, then test them.
The page http://opencv.org/platforms/android.html has lots of info about OpenCV on Android, including links to tutorials.
I have an app that uses custom Exceptions, such as this:
public class SomeException extends Exception{
private int iCode;
private String iMessage;
public SomeException(){
iCode = 201;
iMessage = **//Get the localized string R.string.error_201??**
}
#Override
public String getMessage() {
return iMessage;
}
#Override
public int getCode() {
return iCode;
}
}
Obviously, I want lo localize the error message. I have possible solutions but non of them satisfy me.
1) Pass "Context" to the constructor, and do ctx.getString(R.string.error_201)
--> Fail, as this Exceptions are sometimes thrown from MODEL classes, so they don't have a Context
2) Pass "Context" when retriveing the message in getMessage() function,
--> Fail, It's necesary to override the super method, to work as all other Exceptions.
Solution I have now: All activities in my app have this onCreate:
public void onCreate(...){
Utils.RESOURCES = getResources();
...
}
Very dirty code... I don't like the solution. My question is then,: is there a way to access the resources without the Context? And most important, How would an application such as mine solve this problem?
What about
public class MyException extends Exception {
private int iCode;
public MyException(int code) {
this.iCode = code;
}
#Override
public String getMessage() {
return "MyException code " + String.valueOf(iCode);
}
public String getLocalizedMessage(Context ctx) {
String message;
if (iCode == 201)
message = ctx.getString(R.string.error_201);
else if (iCode == 202)
message = ctx.getString(R.string.error_202);
// ...
}
}
Even if there was way to access context in different way, you should not do it. If you need to emit exceptions where you cannot pass Context, you should be able to access context before you display such error. I cannot see reason why you should create localized error messages from constructor. You can log to logcat not localized versions if you need. And where you want to display something in UI, you should have context at hand.
You can access only system wide resources without Context.
You need a Context, so I would suggest You to get it as soon as possible, and make it available through a static method or variable. You do the same thing in every Activity, but there is a cleaner method. You should make a custom Application, and override its onCreate() to make the resources public:
public class App extends Application {
private static Resources myResources;
#Override
public void onCreate() {
myResources = getBaseContext().getResources();
super.onCreate();
}
public static Resources getMyResources(){
return myResources;
}
}
The other thing you have to do is to set the Application in your manifest:
<application
android:name="{your_package}.App"
...
Now you can access the resources in all of your Activity without any preparation. Your custom Exception class could also use the externalized resources.
I am not sure I did the right thing. The main reason for my doubts is that I cannot find, in this or other forums, someone who has done a similar thing.
I created an abstract java class in my project. Named it lib. I put there several structures and methods used by all other classes in the project.
It works for me, but I want to know if there is a more accepted method of gathering all common methods and structures.
Note: All methods of course are declared as public static.
Note II: I did not know how to get the context within the abstract class, so if needed I had to pass it as argument to the method.
Is this wat you are looking for?
public abstract class AbstractActivity extends Activity{
public static synchronized boolean showAlertBox(Context ctx,final String title,final String message,final String okBtnTxt,final OnClickListener clickListener){
AlertDialog.Builder alertbox; alertbox = new AlertDialog.Builder(ctx);
this.runOnUiThread(new Runnable() {
#Override
public void run() {
alertbox.setTitle(title);
alertbox.setMessage(message);
if(okBtnTxt!=null || clickListener!=null)
alertbox.setNeutralButton(okBtnTxt,clickListener);
alertbox.show();
.....
}
});
return true;
}
}
In the class extending this abstract class you can just call it by using showAlertBox(this);
Other wise use AbstractActivity.showAlertBox(Context);
Well, thanks to #Matt Wolfe's comment I came to know that what I did is called "Utility class" and it is widely used to share common code in a project.
The general template is:
public abstract class lib {
public static final int ZERO = 0;
public static final int ONE = 1;
public static final int TWO = 2;
public static void func1(int i) {
}
public static void func2(int i, String s) {
}
}
and you can use it like this from any other code:
...;
lib.func1( lib.ZERO );
lib func2( lib.TWO, "sandwich" );
...;
Knowing that makes me confident that what I did is OK.
It would be perfect to find a way to avoid the prefix lib. and just have ECLIPSE, and the compiler, find the right import and recognize the function with just its name, like they do for global libraries.