美文网首页安卓系统源码
Android native应用开发简明教程 (2) - 本地应

Android native应用开发简明教程 (2) - 本地应

作者: Jtag特工 | 来源:发表于2017-02-28 21:40 被阅读269次

    本地应用原理

    从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中配置

    最后,我们来看一张图来复习一下:

    ANativeActivity procedure

    相关文章

      网友评论

        本文标题:Android native应用开发简明教程 (2) - 本地应

        本文链接:https://www.haomeiwen.com/subject/lzffgttx.html