NDK层获取Application对象

来源:互联网 发布:徐州淘宝打包员招聘 编辑:程序博客网 时间:2024/06/05 00:20
参考了一位大牛的博客,在Java层通过RuntimeInit获取的方式实现的,先贴原链接:
http://blog.csdn.net/l173864930/article/details/46919457
https://github.com/boyliang/Hijack_AMS_broadIntent
说明缘由,可能会有人提出调用NDK层方法时,自动会获得JNIEnv指针和jobject对象,其中jobject对应的便是Context,可现在的需求是可能出现得不到JNIEnv指针和jobject对象,比如so一加载的时候,就想获取一些系统服务,此时还没有开始调用方法,便得不到这两个需要的对象。


首先说明JNIEnv指针,这个网上有很多的方法获得,我的做法是调用JNI_OnLoad函数,获取JavaVM(当然有其他方式获取),调用GetEnv方法便可获取...比较熟知,不再赘述。贴下代码:
jint JNI_OnLoad(JavaVM* jVm, void* reserved) {    jint result = JNI_ERR;    JNIEnv* env;    if ((*jVm)->GetEnv(jVm,(void**) &env, JNI_VERSION_1_6) != JNI_OK) {        return result;    }    result = JNI_VERSION_1_6;    return result;}

对于Application对象,大牛的博客已经实现了Java层的获取,这里贴下伪代码:
Applicatioin app = RuntimeInit.mApplicationObject.this$0.mInitialApplication;
详细的过程可以去看看

NDK层中如何获取呢?
我想到了两种做法
第一种做法,既然Java层代码(翻查上面链接)能够获取了,直接编个APK,通过DexClassLoader加载APK,调用其中的类方法...但是一直提示找不到类,之前使用AS编译出来的一直有问题,后来使用Eclipse编译出来的apk没有问题,应该是dex文件结构有所变化...有空再细看
jobject SerachContextByJava(JNIEnv *env){    jstring js_apkpath = (*env)->NewStringUTF(env,"/sdcard/getApplicationContext.apk");    jstring js_odexpath = (*env)->NewStringUTF(env,"/data/data/com.ndk/");    jclass cls_dexloader = (*env)->FindClass(env,"dalvik/system/DexClassLoader");    snprintf(sig_buffer, 512, "(%s%s%s%s)V", JSTRING, JSTRING, JSTRING, "Ljava/lang/ClassLoader;");    jmethodID met_dexloader_init = (*env)->GetMethodID(env,cls_dexloader, "<init>", sig_buffer);    snprintf(sig_buffer, 512, "(%s)%s", JSTRING, JCLASS);    jmethodID met_loadClass = (*env)->GetMethodID(env,cls_dexloader, "loadClass", sig_buffer);    jclass cls_classloader = (*env)->FindClass(env,"java/lang/ClassLoader");    snprintf(sig_buffer, 512, "()%s", "Ljava/lang/ClassLoader;");    jmethodID met_getSystemClassLoader = (*env)->GetStaticMethodID(env,cls_classloader, "getSystemClassLoader", sig_buffer);    jobject obj_systemclassloader =  (*env)->CallStaticObjectMethod(env,cls_classloader, met_getSystemClassLoader);    (*env)->DeleteLocalRef(env,cls_classloader);    if(ObjIsNull(obj_systemclassloader,"obj_systemclassloader"))    {        return NULL;    }    jobject obj_dexclassloader = (*env)->NewObject(env,cls_dexloader, met_dexloader_init, js_apkpath, js_odexpath, NULL, obj_systemclassloader);    (*env)->DeleteLocalRef(env,js_apkpath);    (*env)->DeleteLocalRef(env,js_odexpath);    (*env)->DeleteLocalRef(env,cls_dexloader);    (*env)->DeleteLocalRef(env,obj_systemclassloader);    if(ObjIsNull(obj_dexclassloader,"obj_dexclassloader"))    {        (*env)->DeleteLocalRef(env,obj_dexclassloader);        return NULL;    }    jstring js_GetContext = (*env)->NewStringUTF(env,"com.example.runjni.GetContext");    jobject cls_GetContext = ((*env)->CallObjectMethod(env,obj_dexclassloader, met_loadClass, js_GetContext));    (*env)->DeleteLocalRef(env,obj_dexclassloader);    (*env)->DeleteLocalRef(env,js_GetContext);    if(ObjIsNull(cls_GetContext,"cls_GetContext"))    {        (*env)->DeleteLocalRef(env,cls_GetContext);        return NULL;    }    jmethodID met_searchContextForZygoteProcess = (*env)->GetStaticMethodID(env,cls_GetContext, "searchContextForZygoteProcess", "()Landroid/content/Context;");    jobject applicationcontext = (*env)->CallStaticObjectMethod(env,cls_GetContext, met_searchContextForZygoteProcess);    (*env)->DeleteLocalRef(env,cls_GetContext);    if(ObjIsNull(applicationcontext,"applicationcontext"))    {        (*env)->DeleteLocalRef(env,applicationcontext);        return NULL;    }    __android_log_print(ANDROID_LOG_ERROR,"r-ndk","END Serach Context By Java");    return applicationcontext;}


第二种做法,也是基于Java层代码,通过C层API调用Java层的方法来实现。
jobject SearchContextByC(JNIEnv *env){    jstring js_RuntimeInit = (*env)->NewStringUTF(env,"com.android.internal.os.RuntimeInit");    jclass cls_class = (*env)->FindClass(env, "java/lang/Class");    snprintf(sig_buffer, 512, "(%s)%s", JSTRING,JCLASS);    jmethodID met_forName = (*env)->GetStaticMethodID(env,cls_class, "forName", sig_buffer);    jobject  obj_runtime = (*env)->CallStaticObjectMethod(env,cls_class, met_forName,js_RuntimeInit);    (*env)->DeleteLocalRef(env,js_RuntimeInit);    if(ObjIsNull(obj_runtime,"obj_runtime"))    {        (*env)->DeleteLocalRef(env,cls_class);        (*env)->DeleteLocalRef(env,obj_runtime);        return NULL;    }    jstring js_getApplicationObject = (*env)->NewStringUTF(env,"getApplicationObject");    snprintf(sig_buffer, 512, "(%s%s)%s", JSTRING,JCLASS_ARR,JMETHOD);    jmethodID met_getDeclaredMethod = (*env)->GetMethodID(env,cls_class, "getDeclaredMethod", sig_buffer);    jobject obj_sGetApplicationObject_method =  (*env)->CallObjectMethod(env, obj_runtime, met_getDeclaredMethod,js_getApplicationObject,NULL);    (*env)->DeleteLocalRef(env,js_getApplicationObject);    (*env)->DeleteLocalRef(env,obj_runtime);    if(ObjIsNull(obj_sGetApplicationObject_method,"obj_sGetApplicationObject_method"))    {        (*env)->DeleteLocalRef(env,obj_sGetApplicationObject_method);        (*env)->DeleteLocalRef(env,cls_class);        return NULL;    }    jclass cls_method = (*env)->FindClass(env, "java/lang/reflect/Method");    snprintf(sig_buffer, 512, "(%s%s)%s", JOBJECT,JOBJECT_ARR,JOBJECT);    jmethodID met_invoke = (*env)->GetMethodID(env,cls_method, "invoke", sig_buffer);    jobject  obj_applicationobj = (*env)->CallObjectMethod(env,obj_sGetApplicationObject_method, met_invoke,NULL,NULL);    (*env)->DeleteLocalRef(env,cls_method);    (*env)->DeleteLocalRef(env,obj_sGetApplicationObject_method);    if(ObjIsNull(obj_applicationobj,"obj_applicationobj"))    {        (*env)->DeleteLocalRef(env,cls_class);        (*env)->DeleteLocalRef(env,obj_applicationobj);        return NULL;    }    jclass cls_object = (*env)->FindClass(env, "java/lang/Object");    snprintf(sig_buffer, 512, "()%s", JCLASS);    jmethodID met_getClass = (*env)->GetMethodID(env,cls_object, "getClass", sig_buffer);    jobject obj_ApplicatioinThread_class = (*env)->CallObjectMethod(env,obj_applicationobj, met_getClass);    (*env)->DeleteLocalRef(env,cls_object);    if(ObjIsNull(obj_ApplicatioinThread_class,"ApplicatioinThread_class"))    {        (*env)->DeleteLocalRef(env,cls_class);        (*env)->DeleteLocalRef(env,obj_ApplicatioinThread_class);        (*env)->DeleteLocalRef(env,obj_applicationobj);        return NULL;    }    jstring this0 = (*env)->NewStringUTF(env,"this$0");    snprintf(sig_buffer, 512, "(%s)%s", JSTRING,JFIELD);    jmethodID getDeclaredField = (*env)->GetMethodID(env,cls_class, "getDeclaredField", sig_buffer);    jobject obj_sThis0_field =  (*env)->CallObjectMethod(env, obj_ApplicatioinThread_class, getDeclaredField,this0);    (*env)->DeleteLocalRef(env,obj_ApplicatioinThread_class);    (*env)->DeleteLocalRef(env,this0);    (*env)->DeleteLocalRef(env,cls_class);    if(ObjIsNull(obj_sThis0_field,"obj_sThis0_field"))    {        (*env)->DeleteLocalRef(env,obj_sThis0_field);        (*env)->DeleteLocalRef(env,obj_applicationobj);        return NULL;    }    jclass cls_accessibleObject = (*env)->FindClass(env, "java/lang/reflect/AccessibleObject");    snprintf(sig_buffer, 512, "(Z)V");    jmethodID setAccessible = (*env)->GetMethodID(env,cls_accessibleObject, "setAccessible", sig_buffer);    jboolean bool_true = 0x1;    (*env)->CallVoidMethod(env,obj_sThis0_field,setAccessible,bool_true);    (*env)->DeleteLocalRef(env,cls_accessibleObject);    jclass cls_field = (*env)->FindClass(env, "java/lang/reflect/Field");    snprintf(sig_buffer, 512, "(%s)%s",JOBJECT,JOBJECT);    jmethodID get_field = (*env)->GetMethodID(env,cls_field, "get", sig_buffer);    jobject obj_activityObjThr = (*env)->CallObjectMethod(env, obj_sThis0_field, get_field,obj_applicationobj);    (*env)->DeleteLocalRef(env,obj_sThis0_field);    (*env)->DeleteLocalRef(env,obj_applicationobj);    (*env)->DeleteLocalRef(env,cls_field);    if(ObjIsNull(obj_activityObjThr,"obj_activityObjThr"))    {        (*env)->DeleteLocalRef(env,obj_activityObjThr);        return NULL;    }    snprintf(sig_buffer, 512, "()%s", JCLASS);    jobject obj_ActivityThread_class = (*env)->CallObjectMethod(env,obj_activityObjThr, met_getClass);    if(ObjIsNull(obj_ActivityThread_class,"obj_ActivityThread_class"))    {        (*env)->DeleteLocalRef(env,obj_activityObjThr);        (*env)->DeleteLocalRef(env,obj_ActivityThread_class);        return NULL;    }    jstring mInitialApplication = (*env)->NewStringUTF(env,"mInitialApplication");    jobject sInitialApplication_field =  (*env)->CallObjectMethod(env, obj_ActivityThread_class, getDeclaredField,mInitialApplication);    (*env)->DeleteLocalRef(env,obj_ActivityThread_class);    (*env)->DeleteLocalRef(env,mInitialApplication);    if(ObjIsNull(sInitialApplication_field,"sInitialApplication_field"))    {        (*env)->DeleteLocalRef(env,obj_activityObjThr);        (*env)->DeleteLocalRef(env,sInitialApplication_field);        return NULL;    }    (*env)->CallVoidMethod(env,sInitialApplication_field,setAccessible,bool_true);    jobject applicationContext = (*env)->CallObjectMethod(env, sInitialApplication_field, get_field,obj_activityObjThr);    (*env)->DeleteLocalRef(env,obj_activityObjThr);    (*env)->DeleteLocalRef(env,sInitialApplication_field);    if(ObjIsNull(applicationContext,"applicationContext"))    {        (*env)->DeleteLocalRef(env,applicationContext);        return NULL;    }    __android_log_print(ANDROID_LOG_VERBOSE,"r-ndk","END Search Context from C");    return applicationContext;}


做法不难,就是写着挺麻烦,测试5.1,6.0都没问题,贴出来方便大家使用,有更好的方法欢迎推荐。

遇到了一个其他的问题,感觉似乎无法解决,当在fork出一个子进程时,通过此方法去获取系统服务时,进一步操作会出现崩溃的情况,提示的是Couldn't find ProcessRecord for pid xxx
pid对应是子进程id,查了一下相关的资料,搜到了这篇讲述的情况,大概是因为会根据pid查找自己的前世ProcessRecord,ProcessRecord会对应实例app,因此找不到。
http://blog.csdn.net/maxleng/article/details/5621345


转载请注明出处。



1 0
原创粉丝点击