2011年10月31日星期一

mistaken usage of a core class

Android工程在编译生成dex文件时dx有时候会出现下面的错误信息:
2.2-froyo中是
trouble processing "javax/Foo.class":
Attempt to include a core class (java.* or javax.*) in something other than a core library.......

2.3-gingerbread中是
trouble processing "javax/Foo.class":
Ill-advised or mistaken usage of a core class (java.* or javax.*)
when not building a core library.

原因是从安全性和完整性考虑,Android(Java有吗?)不允许从外部引用Java的核心库(java.*或javax.*)。更详细的解释参考http://code.google.com/p/android/issues/detail?id=13084#c2
但其实并不是所有的javax.*都不允许。dx的代码com/android/dx/command/dexer/Main.java中,保存了一个“黑名单”来过滤javax的包。

private static final String[] JAVAX_CORE = {
       "accessibility", "crypto", "imageio", "management", "naming", "net",
       "print", "rmi", "security", "sound", "sql", "swing", "transaction",
       "xml"
   };

那么如果Android并没有提供某些核心库而又必须要使用到这些库的情况下,该如何处理呢?一般来说都是通过repackage来重命名包。
1. 有源码的情况下,可以直接修改源代码。(通过ecllipse的改名重构是一个很好的方法)
2. 如果使用的第三方的jar包,则可以通过工具jarjar进行repackage。

2011年10月27日星期四

Android framework注册native方法流程

Android framework有许多使用JNI的地方,但与一般的应用程序注册方法有所不同,framework中通过startReg()统一进行注册。startReg()函数的实现在AndroidRuntime.cpp。
startReg()调用register_jni_procs(gRegJNI, NELEM(gRegJNI), env)。其中 gRegJNI是一个数组,保存各个java类对应的native犯法注册函数的指针。

以BinderProxy为例:
native方法的注册函数是android_util_Binder.cpp的register_android_os_Binder(),这个函数保存在gRegJNI中。经过层层调用后,最终使用jni的RegisterNatives()来完成注册。
android_util_Binder.cpp的register_android_os_Binder() --->
android_util_Binder.cpp的int_register_android_os_BinderProxy() --->
AndroidRuntime::registerNativeMethods() --->
JNIHelp.c的jniRegisterNativeMethods() --->
jni的RegisterNatives()

RegisterNatives所需要的参数是静态变量保存:
android_util_Binder.cpp中,
char* kBinderProxyPathName保存类名
JNINativeMethod gBinderProxyMethods[]保存类中方法的名字、signatures、native方法的指针。

2011年10月20日星期四

Function Object

Function Object(函数对象)顾名思义,就是用法上类似函数,但语法上来说,仍然是一个对象。
相对于函数指针,Function Object有2个优点:
1. 可以保存状态。作为一个对象,Function Object像普通的对象一样可以通过成员保存状态。
2。可以作为模板参数。

C++中,重载了operator()的类实例化的对象就是一个Function Object
例子:
class Sum { 		int val; 	public: 		Sum(int i) :val(i) { } 		operator int() const { return val; }		// extract value  		int operator()(int i) { return val+=i; }	// application 	};  	void f(vector v) 	{ 		Sum s = 0;	// initial value 0 		s = for_each(v.begin(), v.end(), s);	// gather the sum of all elements 		cout << "the sum is " << s << "\n"; 	 		// or even: 		cout << "the sum is " << for_each(v.begin(), v.end(), Sum(0)) << "\n"; 	} 
}