Android native应用开发简明教程 (2) - 本地应用的原理
2017-03-01 11:57
489 查看
本地应用原理
从NativeActivity说起
本地App,本质上是一个Java App调用了一个JNI的库,而应用的逻辑通过native代码来实现。NativeActivity是继承自Activity的一个类,代码在:/frameworks/base/core/java/android/app/NativeActivity.java中:
public class NativeActivity extends Activity implements SurfaceHolder.Callback2,InputQueue.Callback, OnGlobalLayoutListener{ ...
然后我们再看NativeActivity的onCreate方法:
@Override protected void onCreate(Bundle savedInstanceState) { String libname = "main"; String funcname = "ANativeActivity_onCreate"; ActivityInfo ai; ...
这里我们就看到了一个重要的函数:ANativeActivity_onCreate,这个函数将是本地应用的入口函数。
... try { ai = getPackageManager().getActivityInfo( getIntent().getComponent(), PackageManager.GET_META_DATA); if (ai.metaData != null) { String ln = ai.metaData.getString(META_DATA_LIB_NAME); if (ln != null) libname = ln; ln = ai.metaData.getString(META_DATA_FUNC_NAME); if (ln != null) funcname = ln; } } catch (PackageManager.NameNotFoundException e) { throw new RuntimeException("Error getting activity info", e); } BaseDexClassLoader classLoader = (BaseDexClassLoader) getClassLoader(); String path = classLoader.findLibrary(libname); ...
大家还记得上一讲我们贴的AndroidManifest.xml吗?记得这一行meta data吗:
<!-- Tell NativeActivity the name of our .so --> <meta-data android:name="android.app.lib_name" android:value="native-activity" />
我们的本地应用生成的so库的名字,就是通过这里来读出来的。
最后,通用本地代码的入口在这里:
mNativeHandle = loadNativeCode(path, funcname, Looper.myQueue(), getAbsolutePath(getFilesDir()), getAbsolutePath(getObbDir()), getAbsolutePath(getExternalFilesDir(null)), Build.VERSION.SDK_INT, getAssets(), nativeSavedState, classLoader, classLoader.getLdLibraryPath());
入口点函数是funcname,大家还记得它的定义吧:
String funcname = "ANativeActivity_onCreate"; ... ln = ai.metaData.getString(META_DATA_FUNC_NAME); if (ln != null) funcname = ln;
默认情况下,这个入口函数就是ANativeActivity_onCreate.
JNI层的实现
我们继续跟进去看jni中对于loadNativeCode_native的调用:loadNativeCode_native(JNIEnv* env, jobject clazz, jstring path, jstring funcName, jobject messageQueue, jstring internalDataDir, jstring obbDir, jstring externalDataDir, jint sdkVersion, jobject jAssetMgr, jbyteArray savedState, jobject classLoader, jstring libraryPath) { ...
下面,根据funcName,就是默认是ANativeActivity_onCreate的这个函数,将变成函数指针,类型为ANativeActivity_createFunc
... void* funcPtr = NULL; const char* funcStr = env->GetStringUTFChars(funcName, NULL); if (needNativeBridge) { funcPtr = NativeBridgeGetTrampoline(handle, funcStr, NULL, 0); } else { funcPtr = dlsym(handle, funcStr); } code.reset(new NativeCode(handle, (ANativeActivity_createFunc*)funcPtr)); env->ReleaseStringUTFChars(funcName, funcStr); if (code->createActivityFunc == NULL) { ALOGW("ANativeActivity_onCreate not found"); return 0; } ...
android_native_app_glue的实现
我们再来看看NDK中的android_native_app_glue中,入口函数ANativeActivity_onCreate都做了些什么:void ANativeActivity_onCreate(ANativeActivity* activity, void* savedState, size_t savedStateSize) { LOGV("Creating: %p\n", activity); activity->callbacks->onDestroy = onDestroy; activity->callbacks->onStart = onStart; activity->callbacks->onResume = onResume; activity->callbacks->onSaveInstanceState = onSaveInstanceState; activity->callbacks->onPause = onPause; activity->callbacks->onStop = onStop; activity->callbacks->onConfigurationChanged = onConfigurationChanged; activity->callbacks->onLowMemory = onLowMemory; activity->callbacks->onWindowFocusChanged = onWindowFocusChanged; activity->callbacks->onNativeWindowCreated = onNativeWindowCreated; activity->callbacks->onNativeWindowDestroyed = onNativeWindowDestroyed; activity->callbacks->onInputQueueCreated = onInputQueueCreated; activity->callbacks->onInputQueueDestroyed = onInputQueueDestroyed; activity->instance = android_app_create(activity, savedState, savedStateSize); }
可以看到,这个封装中,除了设置了若干个callback函数以外,就是封装成了android_app_create函数。
我们再来看android_app_create的实现:
static struct android_app* android_app_create(ANativeActivity* activity, void* savedState, size_t savedStateSize) { struct android_app* android_app = (struct android_app*)malloc(sizeof(struct android_app)); memset(android_app, 0, sizeof(struct android_app)); android_app->activity = activity; pthread_mutex_init(&android_app->mutex, NULL); pthread_cond_init(&android_app->cond, NULL); if (savedState != NULL) { android_app->savedState = malloc(savedStateSize); android_app->savedStateSize = savedStateSize; memcpy(android_app->savedState, savedState, savedStateSize); } int msgpipe[2]; if (pipe(msgpipe)) { LOGE("could not create pipe: %s", strerror(errno)); return NULL; } android_app->msgread = msgpipe[0]; android_app->msgwrite = msgpipe[1]; pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); pthread_create(&android_app->thread, &attr, android_app_entry, android_app); // Wait for thread to start. pthread_mutex_lock(&android_app->mutex); while (!android_app->running) { pthread_cond_wait(&android_app->cond, &android_app->mutex); } pthread_mutex_unlock(&android_app->mutex); return android_app; }
这个封装处理了线程安全相关的问题,创新主线程来执行android_app_entry函数。
static void* android_app_entry(void* param) { struct android_app* android_app = (struct android_app*)param; android_app->config = AConfiguration_new(); AConfiguration_fromAssetManager(android_app->config, android_app->activity->assetManager); print_cur_config(android_app); android_app->cmdPollSource.id = LOOPER_ID_MAIN; android_app->cmdPollSource.app = android_app; android_app->cmdPollSource.process = process_cmd; android_app->inputPollSource.id = LOOPER_ID_INPUT; android_app->inputPollSource.app = android_app; android_app->inputPollSource.process = process_input; ALooper* looper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS); ALooper_addFd(looper, android_app->msgread, LOOPER_ID_MAIN, ALOOPER_EVENT_INPUT, NULL, &android_app->cmdPollSource); android_app->looper = looper; pthread_mutex_lock(&android_app->mutex); android_app->running = 1; pthread_cond_broadcast(&android_app->cond); pthread_mutex_unlock(&android_app->mutex); android_main(android_app); android_app_destroy(android_app); return NULL; }
这一层的封装,将处理AConfiguration。但是最主要的是要处理ALooper,构建一个消息队列。
最终才会调用android_main,这一层才是android_native_app_glue封装好的对外接口。
小结
Android支持通过本质上是个so的本地代码来写应用骨架代码是Android framework中的NativeActivity,该类通过装载so库的方式来调用本地应用代码
默认的入口点在ANativeActivity_onCreate,函数名和库名都可以在AndroidManifest.xml中配置
最后,我们来看一张图来复习一下:
相关文章推荐
- Android native应用开发简明教程 (1) - 本地开发武器库概览
- Android简明开发教程三:第一个应用Hello World
- Android简明开发教程二十三:发布应用
- Android简明开发教程二十三:发布应用
- Android简明开发教程二十三:发布应用
- Android简明开发教程二十三:发布应用
- Android简明开发教程二十三:发布应用
- Android简明开发教程三:第一个应用Hello World
- Android简明开发教程四:Android应用基本概念
- Android简明开发教程十七:Dialog 显示图像
- Android简明开发教程十六:Button 画刷示例
- Flash Mobile)使用Flash Builder “Burrito”开发Android应用的入门教程
- Android简明开发教程十二:引路蜂二维图形库简介及颜色示例
- Android简明开发教程十五:RadioButton 多边形及路径绘制
- Android简明开发教程十三:Option Menu 画笔示例
- Android简明开发教程十四:Context Menu 绘制几何图形
- Android简明开发教程十七:Dialog 显示图像
- Android简明开发教程十五:RadioButton 多边形及路径绘制
- Android简明开发教程二:安装开发环境
- Android简明开发教程六:用户界面设计