日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

chromium net android移植

發布時間:2024/4/11 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 chromium net android移植 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Chromium net是chromium瀏覽器及ChromeOS中,用于從網絡獲取資源的模塊。這個網絡庫是用C++編寫的,且用了大量的C++11特性。它廣泛地支持當前互聯網環境中用到的大量的網絡協議,如HTTP/1.1,SPDY,HTTP/2,FTP,QUIC,WebSockets等;在安全性方面也有良好的支持,如SSL等;同時,針對性能,它也有諸多的優化,如引入libevent的基于事件驅動的設計。從而,將chromium net庫移植到android平臺上并用起來,以提升我們的APP的網絡訪問性能成為了一件非常有價值的事情。

這里我們就嘗試將chromium net移植到android平臺上并用起來。但由于龐大的chromium項目有著自己比較特別的開發流程,開發方式,而給我們的移植工作制造了一些障礙。具體地說是:

  • gn/gyp + ninja的構建方式;
  • 為了方便開發,chromium的倉庫中包含了構建所需的完整的工具鏈,包括編譯、鏈接的工具,android的SDK和NDK,甚至是STL。這個工具鏈與我們慣常用在項目中的工具鏈多少還是有一點點區別的,這會給我們的編譯鏈接等制造一些困擾。

但好在Google出品比較具有hack風,因而移植工作的難度變得可控。比如gn工具,可以讓我們比較方便地對工程做更多的探索,我們可以通過這個工具來了解我們編譯一個模塊時,整個環境的配置,該模塊具體包含了哪些源文件,模塊導出的頭文件,編譯鏈接時都用了什么樣的參數等等。

在具體移植開始之前,先設定我們移植的目標:

  • 讓chromium的net模塊可以單獨地在android平臺上跑起來,可以通過JNI的方式進行調用;
  • 將chromium net模塊從整個的chromium代碼庫中抽離,依然基于gn + ninja,建立獨立的開發環境,可以進行配置、構建,以方便后續針對chromium net的開發。
  • 針對與移動端上受限的資源,及項目的需要,對chromium net進行一些裁剪瘦身,比如對ftp協議的支持就沒有太大的必要,砍掉這些用不到的東西以節省資源,提升效能。

這里主要就基于我們的目標,來探索移植的方法。本文不是一份呈送給老板們看的final summary,只能包含簡短的需要做的正確的事情。而是從工程師的直覺出發,逐步的探索整個的移植過程,以方便后續可以輕松地復制移植的過程。本文會記錄遇到的每個問題,并給出出錯的提示,比如編譯器報的error,鏈接器報的error,運行時崩潰抓到的backtrace等等,還會給出對問題的基本分析與定位,及問題的解決方法。

編譯chromium net模塊

首先要做的事情就是下載完整的chromium代碼,這可以參考Chromium Android編譯指南來完成。然后執行(假設當前目錄是chromium代碼庫的根目錄)命令:

$ gclient runhooks $ cd src $ ./build/install-build-deps.sh $ ./build/install-build-deps-android.sh

下載構建chromium所需的系統工具。

之后需要對編譯進行配置。編輯out/Default/args.gn文件,并參照Chromium Android編譯指南中的說明,輸入如下內容:

target_os = "android" target_cpu = "arm" # (default) is_debug = true # (default)# Other args you may want to set: is_component_build = true is_clang = true symbol_level = 1 # Faster build with fewer symbols. -g1 rather than -g2 enable_incremental_javac = true # Much faster; experimental

保存退出之后,執行:

$ gn gen out/Default

產生ninja構建所需的各個模塊的ninja文件。隨后輸入如下命令編譯net模塊:

$ ninja -C out/Default net

這個命令會編譯net模塊,及其依賴的所有模塊,包括base,crypto,borringssl,protobuf,icu,url等。可以看一下我們編譯的成果:

$ ls -alh out/Default/ | grep so$ -rwxrwxr-x 1 chrome chrome 1.2M 8月 10 20:55 libbase.cr.so -rwxrwxr-x 1 chrome chrome 98K 8月 10 20:55 libbase_i18n.cr.so -rwxrwxr-x 1 chrome chrome 773K 8月 10 20:54 libboringssl.cr.so -rwxrwxr-x 1 chrome chrome 74K 8月 10 20:55 libcrcrypto.cr.so -rwxrwxr-x 1 chrome chrome 1.3M 8月 10 20:55 libicui18n.cr.so -rwxrwxr-x 1 chrome chrome 902K 8月 10 20:55 libicuuc.cr.so -rwxrwxr-x 1 chrome chrome 4.1M 8月 10 20:59 libnet.cr.so -rwxrwxr-x 1 chrome chrome 122K 8月 10 20:55 libprefs.cr.so -rwxrwxr-x 1 chrome chrome 182K 8月 10 20:55 libprotobuf_lite.cr.so -rwxrwxr-x 1 chrome chrome 90K 8月 10 20:59 liburl.cr.so

總共10個共享庫文件。

在我們的工程的app模塊的jni目錄下為chromium創建文件夾app/src/main/jni/third_party/chromium/libs和app/src/main/jni/third_party/chromium/include,分別用于存放我們編譯出來的共享庫文件和net等模塊導出的頭文件及這些頭文件include的其它頭文件。

這里我們將編譯出來的所有so文件拷貝到app/src/main/jni/third_party/chromium/libs/armeabi和app/src/main/jni/third_party/chromium/libs/armeabi-v7a目錄下:

cp out/Default/*.so /media/data/MyProjects/MyApplication/app/src/main/jni/third_party/chromium/libs/armeabi/ cp out/Default/*.so /media/data/MyProjects/MyApplication/app/src/main/jni/third_party/chromium/libs/armeabi-v7a/

編譯共享庫似乎挺順利。

提取導出頭文件

為了使用net模塊提供的API,我們不可避免地要將net導出的頭文件引入我們的項目。要做到這些,我們首先就需要從chromium工程中提取net導出的頭文件。不像許多其它的C++項目,源代碼文件、私有頭文件及導出頭文件存放的位置被很好地做了區隔,chromium各個模塊的所有頭文件和源代碼文件都是放在一起的。這還是給我們提取導出頭文件的工作帶來了一點麻煩。

這里我們借助于gn工具提供的desc功能(關于gn工具的用法,可以參考GN的使用 - GN工具一文),輸出中如下的這兩段:

$ gn desc out/Default/ net Target //net:net Type: shared_library Toolchain: //build/toolchain/android:armsources//net/base/address_family.cc//net/base/address_family.h ......public[All headers listed in the sources are public.]

編寫腳本來實現。

我們可以傳入[chromium代碼庫的src目錄路徑][輸出目錄的路徑][模塊名],及[保存頭文件的目標目錄路徑]作為參數,來提取模塊的所有導出頭文件,[保存頭文件的目標目錄路徑]參數缺失時默認使用當前目錄,比如:

$ cd /media/data/MyProjects/MyApplication/app/src/main/jni/third_party/chromium/include $ chromium_mod_headers_extracter.py ~/data/chromium_android/src out/Default net

這里一并將該腳本的完整內容貼出來:

#!/usr/bin/env pythonimport os import shutil import sysdef print_usage_and_exit():print sys.argv[0] + " [chromium_src_root]" + "[out_dir]" + " [target_name]" + " [targetroot]"exit(1)def copy_file(src_file_path, target_file_path):if os.path.exists(target_file_path):returnif not os.path.exists(src_file_path):returntarget_dir_path = os.path.dirname(target_file_path)if not os.path.exists(target_dir_path):os.makedirs(target_dir_path)shutil.copy(src_file_path, target_dir_path)def copy_all_files(source_dir, all_files, target_dir):for one_file in all_files:source_path = source_dir + os.path.sep + one_filetarget_path = target_dir + os.path.sep + one_filecopy_file(source_path, target_path)if __name__ == "__main__":if len(sys.argv) < 4 or len(sys.argv) > 5:print_usage_and_exit()chromium_src_root = sys.argv[1]out_dir = sys.argv[2]target_name = sys.argv[3]target_root_path = "."if len(sys.argv) == 5:target_root_path = sys.argv[4]target_root_path = os.path.abspath(target_root_path)os.chdir(chromium_src_root)cmd = "gn desc " + out_dir + " " + target_nameoutputs = os.popen(cmd).readlines()source_start = Falseall_headers = []public_start = Falsepublic_headers = []for output_line in outputs:output_line = output_line.strip()if output_line.startswith("sources"):source_start = Truecontinueelif source_start and len(output_line) == 0:source_start = Falsecontinueelif source_start and output_line.endswith(".h"):output_line = output_line[1:]all_headers.append(output_line)elif output_line == "public":public_start = Truecontinueelif public_start and len(output_line) == 0:public_start = Falsecontinueelif public_start:public_headers.append(output_line)if len(public_headers) == 1:public_headers = all_headersif len(public_headers) > 1:copy_all_files(chromium_src_root, public_headers, target_dir=target_root_path)

Chromium net的簡單使用

參照chromium/src/net/tools/get_server_time/get_server_time.cc的代碼,來編寫簡單的示例程序。首先是JNI(JNI的用法,可以參考android app中使用JNI)的Java層代碼:

package com.example.hanpfei0306.myapplication;public class NetUtils {static {System.loadLibrary("neteasenet");}private static native void nativeSendRequest(String url);public static void sendRequest(String url) {nativeSendRequest(url);} }

然后是native層的JNI代碼,MyApplication/app/src/main/jni/src/NetJni.cpp:

// // Created by hanpfei0306 on 16-8-4. //#include <stdio.h> #include <net/base/network_delegate_impl.h>#include "jni.h"#include "base/at_exit.h" #include "base/json/json_writer.h" #include "base/message_loop/message_loop.h" #include "base/memory/ptr_util.h" #include "base/run_loop.h" #include "base/values.h" #include "net/http/http_response_headers.h" #include "net/proxy/proxy_config_service_fixed.h" #include "net/url_request/url_fetcher.h" #include "net/url_request/url_fetcher_delegate.h" #include "net/url_request/url_request_context.h" #include "net/url_request/url_request_context_builder.h" #include "net/url_request/url_request_context_getter.h" #include "net/url_request/url_request.h"#include "JNIHelper.h"#define TAG "NetUtils"// Simply quits the current message loop when finished. Used to make // URLFetcher synchronous. class QuitDelegate : public net::URLFetcherDelegate { public:QuitDelegate() {}~QuitDelegate() override {}// net::URLFetcherDelegate implementation.void OnURLFetchComplete(const net::URLFetcher* source) override {LOGE("OnURLFetchComplete");base::MessageLoop::current()->QuitWhenIdle();int responseCode = source->GetResponseCode();const net::URLRequestStatus status = source->GetStatus();if (status.status() != net::URLRequestStatus::SUCCESS) {LOGW("Request failed with error code: %s", net::ErrorToString(status.error()).c_str());return;}const net::HttpResponseHeaders* const headers = source->GetResponseHeaders();if (!headers) {LOGW("Response does not have any headers");return;}size_t iter = 0;std::string header_name;std::string date_header;while (headers->EnumerateHeaderLines(&iter, &header_name, &date_header)) {LOGW("Got %s header: %s\n", header_name.c_str(), date_header.c_str());}std::string responseStr;if(!source->GetResponseAsString(&responseStr)) {LOGW("Get response as string failed!");}LOGI("Content len = %lld, response code = %d, response = %s",source->GetReceivedResponseContentLength(),source->GetResponseCode(),responseStr.c_str());}void OnURLFetchDownloadProgress(const net::URLFetcher* source,int64_t current,int64_t total) override {LOGE("OnURLFetchDownloadProgress");}void OnURLFetchUploadProgress(const net::URLFetcher* source,int64_t current,int64_t total) override {LOGE("OnURLFetchUploadProgress");}private:DISALLOW_COPY_AND_ASSIGN(QuitDelegate); };// NetLog::ThreadSafeObserver implementation that simply prints events // to the logs. class PrintingLogObserver : public net::NetLog::ThreadSafeObserver { public:PrintingLogObserver() {}~PrintingLogObserver() override {// This is guaranteed to be safe as this program is single threaded.net_log()->DeprecatedRemoveObserver(this);}// NetLog::ThreadSafeObserver implementation:void OnAddEntry(const net::NetLog::Entry& entry) override {// The log level of the entry is unknown, so just assume it maps// to VLOG(1).const char* const source_type = net::NetLog::SourceTypeToString(entry.source().type);const char* const event_type = net::NetLog::EventTypeToString(entry.type());const char* const event_phase = net::NetLog::EventPhaseToString(entry.phase());std::unique_ptr<base::Value> params(entry.ParametersToValue());std::string params_str;if (params.get()) {base::JSONWriter::Write(*params, &params_str);params_str.insert(0, ": ");} #ifdef DEBUG_ALLLOGI("source_type = %s (id = %u): entry_type = %s : event_phase = %s params_str = %s",source_type, entry.source().id, event_type, event_phase, params_str.c_str()); #endif}private:DISALLOW_COPY_AND_ASSIGN(PrintingLogObserver); };// Builds a URLRequestContext assuming there's only a single loop. static std::unique_ptr<net::URLRequestContext> BuildURLRequestContext(net::NetLog *net_log) {net::URLRequestContextBuilder builder;builder.set_net_log(net_log); //#if defined(OS_LINUX)// On Linux, use a fixed ProxyConfigService, since the default one// depends on glib.//// TODO(akalin): Remove this once http://crbug.com/146421 is fixed.builder.set_proxy_config_service(base::WrapUnique(new net::ProxyConfigServiceFixed(net::ProxyConfig()))); //#endifstd::unique_ptr<net::URLRequestContext> context(builder.Build());context->set_net_log(net_log);return context; }static void NetUtils_nativeSendRequest(JNIEnv* env, jclass, jstring javaUrl) {const char* native_url = env->GetStringUTFChars(javaUrl, NULL);LOGW("Url: %s", native_url);base::AtExitManager exit_manager;LOGW("Url: %s", native_url);GURL url(native_url);if (!url.is_valid() || (url.scheme() != "http" && url.scheme() != "https")) {LOGW("Not valid url: %s", native_url);return;}LOGW("Url: %s", native_url);base::MessageLoopForIO main_loop;QuitDelegate delegate;std::unique_ptr<net::URLFetcher> fetcher =net::URLFetcher::Create(url, net::URLFetcher::GET, &delegate);net::NetLog *net_log = nullptr; #ifdef DEBUG_ALLnet_log = new net::NetLog;PrintingLogObserver printing_log_observer;net_log->DeprecatedAddObserver(&printing_log_observer,net::NetLogCaptureMode::IncludeSocketBytes()); #endifstd::unique_ptr<net::URLRequestContext> url_request_context(BuildURLRequestContext(net_log));fetcher->SetRequestContext(// Since there's only a single thread, there's no need to worry// about when the URLRequestContext gets created.// The URLFetcher will take a reference on the object, and hence// implicitly take ownership.new net::TrivialURLRequestContextGetter(url_request_context.get(),main_loop.task_runner()));fetcher->Start();// |delegate| quits |main_loop| when the request is done.main_loop.Run();env->ReleaseStringUTFChars(javaUrl, native_url); }int jniRegisterNativeMethods(JNIEnv* env, const char *classPathName, JNINativeMethod *nativeMethods, jint nMethods) {jclass clazz;clazz = env->FindClass(classPathName);if (clazz == NULL) {return JNI_FALSE;}if (env->RegisterNatives(clazz, nativeMethods, nMethods) < 0) {return JNI_FALSE;}return JNI_TRUE; }static JNINativeMethod gNetUtilsMethods[] = {NATIVE_METHOD(NetUtils, nativeSendRequest, "(Ljava/lang/String;)V"), };void register_com_netease_volleydemo_NetUtils(JNIEnv* env) {jniRegisterNativeMethods(env, "com/example/hanpfei0306/myapplication/NetUtils",gNetUtilsMethods, NELEM(gNetUtilsMethods)); }// DalvikVM calls this on startup, so we can statically register all our native methods. jint JNI_OnLoad(JavaVM* vm, void*) {JNIEnv* env;if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {LOGE("JavaVM::GetEnv() failed");abort();}register_com_netease_volleydemo_NetUtils(env);return JNI_VERSION_1_6; }

這個文件里,在nativeSendRequest()函數中調用chromium net做了網絡請求,獲取響應,并打印出響應的headers及響應的content。

MyApplication/app/src/main/jni/src/JNIHelper.h中定義了一些宏,以方便native methods的注冊,其具體內容則為:

#ifndef CANDYWEBCACHE_JNIHELPER_H #define CANDYWEBCACHE_JNIHELPER_H#include <android/log.h>#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,TAG ,__VA_ARGS__) #define LOGI(...) __android_log_print(ANDROID_LOG_INFO,TAG ,__VA_ARGS__) #define LOGW(...) __android_log_print(ANDROID_LOG_WARN,TAG ,__VA_ARGS__) #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,TAG ,__VA_ARGS__) #define LOGF(...) __android_log_print(ANDROID_LOG_FATAL,TAG ,__VA_ARGS__)#ifndef NELEM # define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0]))) #endif#define NATIVE_METHOD(className, functionName, signature) \{ #functionName, signature, reinterpret_cast<void*>(className ## _ ## functionName) }#endif //CANDYWEBCACHE_JNIHELPER_H

配置Gradle

要在Android Studio中使用JNI,還需要對Gralde做一些特別的配置,具體可以參考在Android Studio中使用NDK/JNI - 實驗版插件用戶指南一文。這里需要對MyApplication/build.gradleMyApplication/gradle/wrapper/gradle-wrapper.properties,和MyApplication/app/build.gradle這幾個文件做修改。

修改MyApplication/build.gradle文件,最終的內容為:

// Top-level build file where you can add configuration options common to all sub-projects/modules.buildscript {repositories {jcenter()}dependencies {classpath 'com.android.tools.build:gradle-experimental:0.7.0'// NOTE: Do not place your application dependencies here; they belong// in the individual module build.gradle files} }allprojects {repositories {jcenter()} }task clean(type: Delete) {delete rootProject.buildDir }

在這個文件中配置gradle插件的版本為gradle-experimental:0.7.0

修改MyApplication/gradle/wrapper/gradle-wrapper.properties文件,最終的內容為:

#Mon Dec 28 10:00:20 PST 2015 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-all.zip

在這個文件中配置gradle的版本。

修改MyApplication/app/build.gradle文件,最終的內容為:

apply plugin: 'com.android.model.application'model {repositories {libs(PrebuiltLibraries) {chromium_net {headers.srcDir "src/main/jni/third_party/chromium/include"binaries.withType(SharedLibraryBinary) {sharedLibraryFile = file("src/main/jni/third_party/chromium/libs/${targetPlatform.getName()}/libnet.cr.so")}}}}android {compileSdkVersion 23buildToolsVersion "23.0.3"defaultConfig {applicationId "com.example.hanpfei0306.myapplication"minSdkVersion.apiLevel 19targetSdkVersion.apiLevel 21versionCode 1versionName "1.0"}ndk {moduleName "neteasenet"CFlags.addAll(['-I' + file('src/main/jni/third_party/chromium/include/'),])cppFlags.addAll(['-I' + file('src/main/jni/third_party/chromium/include'),])ldLibs.add("android")ldLibs.add("log")ldLibs.add("z")}sources {main {java {source {srcDir "src/main/java"}}jni {source {srcDirs = ["src/main/jni",]}dependencies {library 'chromium_net' linkage 'shared'}}jniLibs {source {srcDirs =["src/main/jni/third_party/chromium/libs",]}}}}buildTypes {debug {ndk {abiFilters.add("armeabi")abiFilters.add("armeabi-v7a")}}release {minifyEnabled falseproguardFiles.add(file("proguard-rules.pro"))ndk {abiFilters.add("armeabi")abiFilters.add("armeabi-v7a")}}}}android.packagingOptions {exclude 'META-INF/INDEX.LIST'exclude 'META-INF/io.netty.versions.properties'} } dependencies {compile fileTree(dir: 'libs', include: ['*.jar'])testCompile 'junit:junit:4.12'compile 'com.jcraft:jzlib:1.1.2'compile 'com.android.support:appcompat-v7:23.4.0' }

我們在這里對native代碼的整個編譯、鏈接做配置。這包括,編譯要包含哪些源文件,編譯時頭文件的搜索路徑,我們的native代碼依賴的要鏈接的系統共享庫/靜態庫,我們的native代碼依賴的要鏈接的預編譯的共享庫/靜態庫,比如我們的chromium net等。配置編譯出來的共享庫的文件名。同時還要為buildTypes配置abiFilters,以防止構建系統嘗試為其它我們不打算支持的ABI,如arm64-v8a、mips、mips64、x86和x86_64,構建共享庫,而發生找不到響應的chromium net的so文件的錯誤。

應用工程編譯

做了上面的配置之后,我們懷著激動的心情,小心翼翼地點擊“Rebuild Project”菜單項,并期待奇跡發生。編譯過程啟動之后,很快就終止了,報出了如下的error:

:app:compileNeteasenetArmeabi-v7aDebugSharedLibraryNeteasenetMainCpp /media/data/MyProjects/MyApplication/app/src/main/jni/src/NetJni.cpp Information:(6) (Unknown) In file included /media/data/MyProjects/MyApplication/app/src/main/jni/third_party/chromium/include/net/base/network_delegate_impl.h Error:(10, 35) base/strings/string16.h: No such file or directory compilation terminated. Error:Execution failed for task ':app:compileNeteasenetArmeabi-v7aDebugSharedLibraryNeteasenetMainCpp'. > A build operation failed.C++ compiler failed while compiling NetJni.cpp.See the complete log at: file:///media/data/MyProjects/MyApplication/app/build/tmp/compileNeteasenetArmeabi-v7aDebugSharedLibraryNeteasenetMainCpp/output.txt Information:BUILD FAILED Information:Total time: 4.239 secs Information:2 errors Information:0 warnings Information:See complete output in console

提示找不到base模塊的頭文件base/strings/string16.h。base模塊是chromium項目中大多數模塊都會依賴的模塊,它提供了許多基本的功能,比如字符串,文件操作,消息隊列MessageQueue,內存管理的一些操作等等。net模塊的頭文件include了base的頭文件的地方還不少,而在我們自己的JNI native層代碼中,也難免要引用到base定義的一些組件,因而我們需要將base模塊導出的頭文件一并引入我們的工程。提取base的頭文件并引入我們的工程:

$ cd /media/data/MyProjects/MyApplication/app/src/main/jni/third_party/chromium/include $ chromium_mod_headers_extracter.py ~/data/chromium_android/src out/Default base

配置stl

引入了base模塊的頭文件之后,再次編譯我們的應用工程。又報error了:

:app:compileNeteasenetArmeabi-v7aDebugSharedLibraryNeteasenetMainCpp /media/data/MyProjects/MyApplication/app/src/main/jni/third_party/chromium/include/net/base/network_delegate_impl.h Information:(10) (Unknown) In file included /media/data/MyProjects/MyApplication/app/src/main/jni/third_party/chromium/include/base/strings/string16.h Error:(33, 22) functional: No such file or directory compilation terminated. Error:Execution failed for task ':app:compileNeteasenetArmeabi-v7aDebugSharedLibraryNeteasenetMainCpp'. > A build operation failed.C++ compiler failed while compiling NetJni.cpp.See the complete log at: file:///media/data/MyProjects/MyApplication/app/build/tmp/compileNeteasenetArmeabi-v7aDebugSharedLibraryNeteasenetMainCpp/output.txt Information:BUILD FAILED Information:Total time: 10.702 secs Information:2 errors Information:0 warnings Information:See complete output in console

這里是提示找不到STL的頭文件。在MyApplication/app/build.gradle中配置stl:

stl "gnustl_static"

引入chromium的build配置頭文件

配置了stl之后,再次編譯我們的應用工程。接著報error:

18:52:21: Executing external task 'assembleDebug'... Observed package id 'build-tools;20.0.0' in inconsistent location '/home/hanpfei0306/data/dev_tools/Android/sdk/build-tools/android-4.4W' (Expected '/home/hanpfei0306/data/dev_tools/Android/sdk/build-tools/20.0.0') Incremental java compilation is an incubating feature. In file included from /media/data/MyProjects/MyApplication/app/src/main/jni/third_party/chromium/include/net/base/network_delegate_impl.h:10:0,from /media/data/MyProjects/MyApplication/app/src/main/jni/src/NetJni.cpp:6: /media/data/MyProjects/MyApplication/app/src/main/jni/third_party/chromium/include/base/strings/string16.h:37:32: fatal error: build/build_config.h: No such file or directory#include "build/build_config.h"^ compilation terminated.:app:compileNeteasenetArmeabi-v7aDebugSharedLibraryNeteasenetMainCpp FAILEDFAILURE: Build failed with an exception.* What went wrong: Execution failed for task ':app:compileNeteasenetArmeabi-v7aDebugSharedLibraryNeteasenetMainCpp'. > A build operation failed.C++ compiler failed while compiling NetJni.cpp.See the complete log at: file:///media/data/MyProjects/MyApplication/app/build/tmp/compileNeteasenetArmeabi-v7aDebugSharedLibraryNeteasenetMainCpp/output.txt* Try: Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.BUILD FAILEDTotal time: 2.773 secs C++ compiler failed while compiling NetJni.cpp. 18:52:24: External task execution finished 'assembleDebug'.

提示找不到"build/build_config.h"文件。這個文件定義了一些全局性的宏,以對編譯做一些全局的控制。這次直接將chromium代碼庫中的對應文件拷貝過來。

引入遺漏的頭文件

再次編譯我們的應用工程。接著報error:

18:55:46: Executing external task 'assembleDebug'... Observed package id 'build-tools;20.0.0' in inconsistent location '/home/hanpfei0306/data/dev_tools/Android/sdk/build-tools/android-4.4W' (Expected '/home/hanpfei0306/data/dev_tools/Android/sdk/build-tools/20.0.0') Incremental java compilation is an incubating feature. In file included from /media/data/MyProjects/MyApplication/app/src/main/jni/third_party/chromium/include/net/base/completion_callback.h:10:0,from /media/data/MyProjects/MyApplication/app/src/main/jni/third_party/chromium/include/net/base/network_delegate_impl.h:11,from /media/data/MyProjects/MyApplication/app/src/main/jni/src/NetJni.cpp:6: /media/data/MyProjects/MyApplication/app/src/main/jni/third_party/chromium/include/base/callback.h:8:35: fatal error: base/callback_forward.h: No such file or directory#include "base/callback_forward.h"^ compilation terminated.:app:compileNeteasenetArmeabi-v7aDebugSharedLibraryNeteasenetMainCpp FAILEDFAILURE: Build failed with an exception.* What went wrong: Execution failed for task ':app:compileNeteasenetArmeabi-v7aDebugSharedLibraryNeteasenetMainCpp'. > A build operation failed.C++ compiler failed while compiling NetJni.cpp.See the complete log at: file:///media/data/MyProjects/MyApplication/app/build/tmp/compileNeteasenetArmeabi-v7aDebugSharedLibraryNeteasenetMainCpp/output.txt* Try: Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.BUILD FAILEDTotal time: 0.663 secs C++ compiler failed while compiling NetJni.cpp. 18:55:47: External task execution finished 'assembleDebug'.

提示找不到base模塊的頭文件base/callback_forward.h。直接將chromium代碼庫中的對應文件拷貝過來。我們似乎是被gn desc的輸出欺騙了,它似乎并沒有將一個模塊導出的所有的頭文件都告訴我們。像 base/callback_forward.h 一樣,逃過了gn desc 的眼睛,同時也逃過了我們提取模塊頭文件的腳本的眼睛的頭文件還有如下的這些:

base/message_loop/timer_slack.h base/files/file.h net/cert/cert_status_flags_list.h net/cert/cert_type.h net/base/privacy_mode.h net/websockets/websocket_event_interface.h net/quic/quic_alarm_factory.h

這里我們就不將缺少這些文件導致的錯誤的錯誤輸出列出來了,內容與前面看到的缺少base/callback_forward.h文件導致的錯誤的錯誤輸出類似,解決的方法也相同。

算下來,我們提取模塊的頭文件的腳本遺漏了8個頭文件。不能不讓人感慨,移植這個事情真是個體力活啊。不過還好遺漏的不是80個文件,或800個,要不然真是要把人逼瘋了。

引入url模塊的導出頭文件

引入了那些遺漏的頭文件之后,再次編譯。繼續報錯:

18:57:46: Executing external task 'assembleDebug'... Observed package id 'build-tools;20.0.0' in inconsistent location '/home/hanpfei0306/data/dev_tools/Android/sdk/build-tools/android-4.4W' (Expected '/home/hanpfei0306/data/dev_tools/Android/sdk/build-tools/20.0.0') Incremental java compilation is an incubating feature. In file included from /home/hanpfei0306/data/dev_tools/Android/android-ndk-r12b/sources/cxx-stl/gnu-libstdc++/4.9/include/atomic:38:0,from /media/data/MyProjects/MyApplication/app/src/main/jni/third_party/chromium/include/base/atomicops_internals_portable.h:35,from /media/data/MyProjects/MyApplication/app/src/main/jni/third_party/chromium/include/base/atomicops.h:152,from /media/data/MyProjects/MyApplication/app/src/main/jni/third_party/chromium/include/base/atomic_ref_count.h:11,from /media/data/MyProjects/MyApplication/app/src/main/jni/third_party/chromium/include/base/callback_internal.h:11,from /media/data/MyProjects/MyApplication/app/src/main/jni/third_party/chromium/include/base/callback.h:9,from /media/data/MyProjects/MyApplication/app/src/main/jni/third_party/chromium/include/net/base/completion_callback.h:10,from /media/data/MyProjects/MyApplication/app/src/main/jni/third_party/chromium/include/net/base/network_delegate_impl.h:11,from /media/data/MyProjects/MyApplication/app/src/main/jni/src/NetJni.cpp:6: /home/hanpfei0306/data/dev_tools/Android/android-ndk-r12b/sources/cxx-stl/gnu-libstdc++/4.9/include/bits/c++0x_warning.h:32:2: error: #error This file requires compiler and library support for the ISO C++ 2011 standard. This support is currently experimental, and must be enabled with the -std=c++11 or -std=gnu++11 compiler options.#error This file requires compiler and library support for the \^ In file included from /media/data/MyProjects/MyApplication/app/src/main/jni/third_party/chromium/include/net/base/network_delegate.h:15:0,from /media/data/MyProjects/MyApplication/app/src/main/jni/third_party/chromium/include/net/base/network_delegate_impl.h:12,from /media/data/MyProjects/MyApplication/app/src/main/jni/src/NetJni.cpp:6: /media/data/MyProjects/MyApplication/app/src/main/jni/third_party/chromium/include/net/base/auth.h:13:24: fatal error: url/origin.h: No such file or directory#include "url/origin.h"^ compilation terminated.:app:compileNeteasenetArmeabi-v7aDebugSharedLibraryNeteasenetMainCpp FAILEDFAILURE: Build failed with an exception.* What went wrong: Execution failed for task ':app:compileNeteasenetArmeabi-v7aDebugSharedLibraryNeteasenetMainCpp'. > A build operation failed.C++ compiler failed while compiling NetJni.cpp.See the complete log at: file:///media/data/MyProjects/MyApplication/app/build/tmp/compileNeteasenetArmeabi-v7aDebugSharedLibraryNeteasenetMainCpp/output.txt* Try: Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.BUILD FAILEDTotal time: 0.722 secs C++ compiler failed while compiling NetJni.cpp. 18:57:47: External task execution finished 'assembleDebug'.

這次是提示找不到url模塊的頭文件url/origin.h。url模塊與我們要用的net聯系緊密,同樣不可避免地要在我們的native層代碼中引用到。因而我們要將url模塊導出的頭文件一并引入我們的工程。提取url的導出頭文件并引入我們的工程:

$ cd /media/data/MyProjects/MyApplication/app/src/main/jni/third_party/chromium/include $ chromium_mod_headers_extracter.py ~/data/chromium_android/src out/Default url

注釋掉gtest相關代碼

引入了url模塊的導出頭文件之后,再次編譯。繼續報錯:

19:00:48: Executing external task 'assembleDebug'... Observed package id 'build-tools;20.0.0' in inconsistent location '/home/hanpfei0306/data/dev_tools/Android/sdk/build-tools/android-4.4W' (Expected '/home/hanpfei0306/data/dev_tools/Android/sdk/build-tools/20.0.0') Incremental java compilation is an incubating feature. In file included from /home/hanpfei0306/data/dev_tools/Android/android-ndk-r12b/sources/cxx-stl/gnu-libstdc++/4.9/include/atomic:38:0,from /media/data/MyProjects/MyApplication/app/src/main/jni/third_party/chromium/include/base/atomicops_internals_portable.h:35,from /media/data/MyProjects/MyApplication/app/src/main/jni/third_party/chromium/include/base/atomicops.h:152,from /media/data/MyProjects/MyApplication/app/src/main/jni/third_party/chromium/include/base/atomic_ref_count.h:11,from /media/data/MyProjects/MyApplication/app/src/main/jni/third_party/chromium/include/base/callback_internal.h:11,from /media/data/MyProjects/MyApplication/app/src/main/jni/third_party/chromium/include/base/callback.h:9,from /media/data/MyProjects/MyApplication/app/src/main/jni/third_party/chromium/include/net/base/completion_callback.h:10,from /media/data/MyProjects/MyApplication/app/src/main/jni/third_party/chromium/include/net/base/network_delegate_impl.h:11,from /media/data/MyProjects/MyApplication/app/src/main/jni/src/NetJni.cpp:6: /home/hanpfei0306/data/dev_tools/Android/android-ndk-r12b/sources/cxx-stl/gnu-libstdc++/4.9/include/bits/c++0x_warning.h:32:2: error: #error This file requires compiler and library support for the ISO C++ 2011 standard. This support is currently experimental, and must be enabled with the -std=c++11 or -std=gnu++11 compiler options.#error This file requires compiler and library support for the \^ In file included from /media/data/MyProjects/MyApplication/app/src/main/jni/third_party/chromium/include/net/cookies/canonical_cookie.h:12:0,from /media/data/MyProjects/MyApplication/app/src/main/jni/third_party/chromium/include/net/base/network_delegate.h:17,from /media/data/MyProjects/MyApplication/app/src/main/jni/third_party/chromium/include/net/base/network_delegate_impl.h:12,from /media/data/MyProjects/MyApplication/app/src/main/jni/src/NetJni.cpp:6: /media/data/MyProjects/MyApplication/app/src/main/jni/third_party/chromium/include/base/gtest_prod_util.h:8:52: fatal error: testing/gtest/include/gtest/gtest_prod.h: No such file or directory#include "testing/gtest/include/gtest/gtest_prod.h"^ compilation terminated.:app:compileNeteasenetArmeabi-v7aDebugSharedLibraryNeteasenetMainCpp FAILEDFAILURE: Build failed with an exception.* What went wrong: Execution failed for task ':app:compileNeteasenetArmeabi-v7aDebugSharedLibraryNeteasenetMainCpp'. > A build operation failed.C++ compiler failed while compiling NetJni.cpp.See the complete log at: file:///media/data/MyProjects/MyApplication/app/build/tmp/compileNeteasenetArmeabi-v7aDebugSharedLibraryNeteasenetMainCpp/output.txt* Try: Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.BUILD FAILEDTotal time: 0.66 secs C++ compiler failed while compiling NetJni.cpp. 19:00:49: External task execution finished 'assembleDebug'.

這一次是提示找不到gtest的頭文件。暫時我們還無需借助于gtest來做單元測試,因而這個include顯得沒有必要。我們將MyApplication/app/src/main/jni/third_party/chromium/include/base/gtest_prod_util.h文件中對"testing/gtest/include/gtest/gtest_prod.h"的include注釋掉,同時修改FRIEND_TEST_ALL_PREFIXES宏的定義:

#if 0 #define FRIEND_TEST_ALL_PREFIXES(test_case_name, test_name) \FRIEND_TEST(test_case_name, test_name); \FRIEND_TEST(test_case_name, DISABLED_##test_name); \FRIEND_TEST(test_case_name, FLAKY_##test_name) #else #define FRIEND_TEST_ALL_PREFIXES(test_case_name, test_name) #endif

這樣就可以注釋掉類定義中專門為gtest插入的那些代碼了。

配置C++11

再次編譯,繼續報錯:

/media/data/MyProjects/MyApplication/app/src/main/jni/src/NetJni.cpp:166:5: error: 'unique_ptr' is not a member of 'std'std::unique_ptr<net::URLRequestContext> url_request_context(BuildURLRequestContext(net_log));^ /media/data/MyProjects/MyApplication/app/src/main/jni/src/NetJni.cpp:166:43: error: expected primary-expression before '>' tokenstd::unique_ptr<net::URLRequestContext> url_request_context(BuildURLRequestContext(net_log));^ /media/data/MyProjects/MyApplication/app/src/main/jni/src/NetJni.cpp:166:95: error: 'BuildURLRequestContext' was not declared in this scopestd::unique_ptr<net::URLRequestContext> url_request_context(BuildURLRequestContext(net_log));^ /media/data/MyProjects/MyApplication/app/src/main/jni/src/NetJni.cpp:166:96: error: 'url_request_context' was not declared in this scopestd::unique_ptr<net::URLRequestContext> url_request_context(BuildURLRequestContext(net_log));^ In file included from /media/data/MyProjects/MyApplication/app/src/main/jni/third_party/chromium/include/base/files/file_path.h:113:0,from /media/data/MyProjects/MyApplication/app/src/main/jni/third_party/chromium/include/base/files/file.h:13,from /media/data/MyProjects/MyApplication/app/src/main/jni/third_party/chromium/include/net/base/net_errors.h:11,from /media/data/MyProjects/MyApplication/app/src/main/jni/third_party/chromium/include/net/proxy/proxy_config_service_fixed.h:9,from /media/data/MyProjects/MyApplication/app/src/main/jni/src/NetJni.cpp:16: /media/data/MyProjects/MyApplication/app/src/main/jni/third_party/chromium/include/base/containers/hash_tables.h: In instantiation of 'std::size_t base_hash::hash<T>::operator()(const T&) const [with T = std::basic_string<char>; std::size_t = unsigned int]': /media/data/MyProjects/MyApplication/app/src/main/jni/third_party/chromium/include/base/files/file_path.h:473:56: required from here /media/data/MyProjects/MyApplication/app/src/main/jni/third_party/chromium/include/base/containers/hash_tables.h:28:77: error: no match for call to '(std::hash) (const std::basic_string<char>&)'std::size_t operator()(const T& value) const { return std::hash<T>()(value); }^ In file included from /media/data/MyProjects/MyApplication/app/src/main/jni/third_party/chromium/include/net/base/network_delegate_impl.h:10:0,from /media/data/MyProjects/MyApplication/app/src/main/jni/src/NetJni.cpp:6: /media/data/MyProjects/MyApplication/app/src/main/jni/third_party/chromium/include/base/strings/string16.h:194:8: note: candidate is:struct hash<base::string16> {^ /media/data/MyProjects/MyApplication/app/src/main/jni/third_party/chromium/include/base/strings/string16.h:195:15: note: std::size_t std::hash::operator()(const string16&) conststd::size_t operator()(const base::string16& s) const {^ /media/data/MyProjects/MyApplication/app/src/main/jni/third_party/chromium/include/base/strings/string16.h:195:15: note: no known conversion for argument 1 from 'const std::basic_string<char>' to 'const string16& {aka const std::basic_string<short unsigned int, base::string16_char_traits>&}' In file included from /home/hanpfei0306/data/dev_tools/Android/android-ndk-r12b/sources/cxx-stl/gnu-libstdc++/4.9/include/atomic:41:0,from /media/data/MyProjects/MyApplication/app/src/main/jni/third_party/chromium/include/base/atomicops_internals_portable.h:35,from /media/data/MyProjects/MyApplication/app/src/main/jni/third_party/chromium/include/base/atomicops.h:152,from /media/data/MyProjects/MyApplication/app/src/main/jni/third_party/chromium/include/base/atomic_ref_count.h:11,from /media/data/MyProjects/MyApplication/app/src/main/jni/third_party/chromium/include/base/callback_internal.h:11,from /media/data/MyProjects/MyApplication/app/src/main/jni/third_party/chromium/include/base/callback.h:9,from /media/data/MyProjects/MyApplication/app/src/main/jni/third_party/chromium/include/net/base/completion_callback.h:10,from /media/data/MyProjects/MyApplication/app/src/main/jni/third_party/chromium/include/net/base/network_delegate_impl.h:11,from /media/data/MyProjects/MyApplication/app/src/main/jni/src/NetJni.cpp:6: /home/hanpfei0306/data/dev_tools/Android/android-ndk-r12b/sources/cxx-stl/gnu-libstdc++/4.9/include/bits/atomic_base.h: At global scope: /home/hanpfei0306/data/dev_tools/Android/android-ndk-r12b/sources/cxx-stl/gnu-libstdc++/4.9/include/bits/atomic_base.h:588:7: warning: inline function 'bool std::__atomic_base<_IntTp>::compare_exchange_strong(std::__atomic_base<_IntTp>::__int_type&, std::__atomic_base<_IntTp>::__int_type, std::memory_order, std::memory_order) volatile [with _ITp = int; std::__atomic_base<_IntTp>::__int_type = int; std::memory_order = std::memory_order]' used but never definedcompare_exchange_strong(__int_type& __i1, __int_type __i2,^ /home/hanpfei0306/data/dev_tools/Android/android-ndk-r12b/sources/cxx-stl/gnu-libstdc++/4.9/include/bits/atomic_base.h:525:7: warning: inline function 'std::__atomic_base<_IntTp>::__int_type std::__atomic_base<_IntTp>::exchange(std::__atomic_base<_IntTp>::__int_type, std::memory_order) volatile [with _ITp = int; std::__atomic_base<_IntTp>::__int_type = int; std::memory_order = std::memory_order]' used but never definedexchange(__int_type __i,^ /home/hanpfei0306/data/dev_tools/Android/android-ndk-r12b/sources/cxx-stl/gnu-libstdc++/4.9/include/bits/atomic_base.h:624:7: warning: inline function 'std::__atomic_base<_IntTp>::__int_type std::__atomic_base<_IntTp>::fetch_add(std::__atomic_base<_IntTp>::__int_type, std::memory_order) volatile [with _ITp = int; std::__atomic_base<_IntTp>::__int_type = int; std::memory_order = std::memory_order]' used but never definedfetch_add(__int_type __i,^ /home/hanpfei0306/data/dev_tools/Android/android-ndk-r12b/sources/cxx-stl/gnu-libstdc++/4.9/include/bits/atomic_base.h:485:7: warning: inline function 'void std::__atomic_base<_IntTp>::store(std::__atomic_base<_IntTp>::__int_type, std::memory_order) volatile [with _ITp = int; std::__atomic_base<_IntTp>::__int_type = int; std::memory_order = std::memory_order]' used but never definedstore(__int_type __i,^ /home/hanpfei0306/data/dev_tools/Android/android-ndk-r12b/sources/cxx-stl/gnu-libstdc++/4.9/include/bits/atomic_base.h:507:7: warning: inline function 'std::__atomic_base<_IntTp>::__int_type std::__atomic_base<_IntTp>::load(std::memory_order) const volatile [with _ITp = int; std::__atomic_base<_IntTp>::__int_type = int; std::memory_order = std::memory_order]' used but never definedload(memory_order __m = memory_order_seq_cst) const volatile noexcept^:app:compileNeteasenetArmeabi-v7aDebugSharedLibraryNeteasenetMainCpp FAILEDFAILURE: Build failed with an exception.* What went wrong: Execution failed for task ':app:compileNeteasenetArmeabi-v7aDebugSharedLibraryNeteasenetMainCpp'. > A build operation failed.C++ compiler failed while compiling NetJni.cpp.See the complete log at: file:///media/data/MyProjects/MyApplication/app/build/tmp/compileNeteasenetArmeabi-v7aDebugSharedLibraryNeteasenetMainCpp/output.txt* Try: Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.BUILD FAILEDTotal time: 1.482 secs C++ compiler failed while compiling NetJni.cpp. 19:19:25: External task execution finished 'assembleDebug'.

這里提示std命名空間中沒有unique_ptr,沒有hash等,前者是C++11中新添加的智能指針模板,而后者則是哈希模板,它定義一個函數對象,實現散列函數。chromium net中,像這樣用到了C++11的特性的地方還有很多,這里的這個錯誤是由于build.gradle中沒有進行C++11的配置。我們在MyApplication/app/build.gradle中配置C++11:

cppFlags.addAll(['-std=gnu++11'])

不過在前面,我們也有看到如下這樣的錯誤消息:

/home/hanpfei0306/data/dev_tools/Android/android-ndk-r12b/sources/cxx-stl/gnu-libstdc++/4.9/include/bits/c++0x_warning.h:32:2: error: #error This file requires compiler and library support for the ISO C++ 2011 standard. This support is currently experimental, and must be enabled with the -std=c++11 or -std=gnu++11 compiler options.#error This file requires compiler and library support for the \^

如果我們能早些注意到這樣的錯誤消息,做了C++11的配置,大概這里的這個error還是可以避免的。

鏈接

做了C++11的配置之后,再次編譯,繼續報錯:

19:29:04: Executing external task 'assembleDebug'... Observed package id 'build-tools;20.0.0' in inconsistent location '/home/hanpfei0306/data/dev_tools/Android/sdk/build-tools/android-4.4W' (Expected '/home/hanpfei0306/data/dev_tools/Android/sdk/build-tools/20.0.0') Incremental java compilation is an incubating feature. :app:compileNeteasenetArmeabi-v7aDebugSharedLibraryNeteasenetMainCpp /media/data/MyProjects/MyApplication/app/src/main/jni/third_party/chromium/include/base/message_loop/message_loop.h:650: error: undefined reference to 'base::MessageLoop::MessageLoop(base::MessageLoop::Type)' /media/data/MyProjects/MyApplication/app/src/main/jni/src/NetJni.cpp:39: error: undefined reference to 'base::MessageLoop::current()' /media/data/MyProjects/MyApplication/app/src/main/jni/src/NetJni.cpp:39: error: undefined reference to 'base::MessageLoop::QuitWhenIdle()' /media/data/MyProjects/MyApplication/app/src/main/jni/src/NetJni.cpp:56: error: undefined reference to 'net::HttpResponseHeaders::EnumerateHeaderLines(unsigned int*, std::string*, std::string*) const' /media/data/MyProjects/MyApplication/app/src/main/jni/src/NetJni.cpp:140: error: undefined reference to 'base::BasicStringPiece<std::string>::BasicStringPiece(char const*)' /media/data/MyProjects/MyApplication/app/src/main/jni/src/NetJni.cpp:140: error: undefined reference to 'GURL::GURL(base::BasicStringPiece<std::string>)' /media/data/MyProjects/MyApplication/app/src/main/jni/src/NetJni.cpp:171: error: undefined reference to 'base::MessageLoop::Run()' /media/data/MyProjects/MyApplication/app/src/main/jni/src/NetJni.cpp:147: error: undefined reference to 'GURL::~GURL()' /media/data/MyProjects/MyApplication/app/build/intermediates/objectFiles/armeabi-v7aDebugSharedLibrary/neteasenetMainCpp/9a4xqrdajtunvcxs263gsxl2i/NetJni.o:NetJni.cpp:vtable for base::MessageLoopForIO: error: undefined reference to 'base::MessageLoop::DoWork()' /media/data/MyProjects/MyApplication/app/build/intermediates/objectFiles/armeabi-v7aDebugSharedLibrary/neteasenetMainCpp/9a4xqrdajtunvcxs263gsxl2i/NetJni.o:NetJni.cpp:vtable for base::MessageLoopForIO: error: undefined reference to 'base::MessageLoop::DoDelayedWork(base::TimeTicks*)' /media/data/MyProjects/MyApplication/app/build/intermediates/objectFiles/armeabi-v7aDebugSharedLibrary/neteasenetMainCpp/9a4xqrdajtunvcxs263gsxl2i/NetJni.o:NetJni.cpp:vtable for base::MessageLoopForIO: error: undefined reference to 'base::MessageLoop::DoIdleWork()' /media/data/MyProjects/MyApplication/app/build/intermediates/objectFiles/armeabi-v7aDebugSharedLibrary/neteasenetMainCpp/9a4xqrdajtunvcxs263gsxl2i/NetJni.o:NetJni.cpp:vtable for base::MessageLoopForIO: error: undefined reference to 'base::MessageLoop::IsType(base::MessageLoop::Type) const' /media/data/MyProjects/MyApplication/app/src/main/jni/third_party/chromium/include/base/message_loop/message_loop.h:645: error: undefined reference to 'base::MessageLoop::~MessageLoop()' collect2: error: ld returned 1 exit status:app:linkNeteasenetArmeabi-v7aDebugSharedLibrary FAILEDFAILURE: Build failed with an exception.* What went wrong: Execution failed for task ':app:linkNeteasenetArmeabi-v7aDebugSharedLibrary'. > A build operation failed.Linker failed while linking libneteasenet.so.See the complete log at: file:///media/data/MyProjects/MyApplication/app/build/tmp/linkNeteasenetArmeabi-v7aDebugSharedLibrary/output.txt* Try: Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.BUILD FAILEDTotal time: 4.835 secs Linker failed while linking libneteasenet.so. 19:29:09: External task execution finished 'assembleDebug'.

這次是鏈接錯誤,提示找不到base庫和url庫中的符號base::MessageLoop::MessageLoop(base::MessageLoop::Type)GURL::~GURL()base::MessageLoop::DoIdleWork()等。看來經過前面的各種艱難險阻,我們總算是將native層的cpp文件編譯為了.o文件。

為了解決這個問題,我們還需要在MyApplication/app/build.gradle中添加對base和url這兩個庫的依賴:

chromium_base {headers.srcDir "src/main/jni/third_party/chromium/include"binaries.withType(SharedLibraryBinary) {sharedLibraryFile = file("src/main/jni/third_party/chromium/libs/${targetPlatform.getName()}/libbase.cr.so")}}chromium_url {headers.srcDir "src/main/jni/third_party/chromium/include"binaries.withType(SharedLibraryBinary) {sharedLibraryFile = file("src/main/jni/third_party/chromium/libs/${targetPlatform.getName()}/liburl.cr.so")}}......dependencies {library 'chromium_base' linkage 'shared'library 'chromium_url' linkage 'shared'library 'chromium_net' linkage 'shared'}

選擇正確的STL庫

經過了前面的修改,再次編譯,然而......繼續報錯:

19:35:16: Executing external task 'assembleDebug'... Observed package id 'build-tools;20.0.0' in inconsistent location '/home/hanpfei0306/data/dev_tools/Android/sdk/build-tools/android-4.4W' (Expected '/home/hanpfei0306/data/dev_tools/Android/sdk/build-tools/20.0.0') Incremental java compilation is an incubating feature. :app:compileNeteasenetArmeabi-v7aDebugSharedLibraryNeteasenetMainCpp UP-TO-DATE /media/data/MyProjects/MyApplication/app/src/main/jni/src/NetJni.cpp:56: error: undefined reference to 'net::HttpResponseHeaders::EnumerateHeaderLines(unsigned int*, std::string*, std::string*) const' /media/data/MyProjects/MyApplication/app/src/main/jni/src/NetJni.cpp:140: error: undefined reference to 'base::BasicStringPiece<std::string>::BasicStringPiece(char const*)' /media/data/MyProjects/MyApplication/app/src/main/jni/src/NetJni.cpp:140: error: undefined reference to 'GURL::GURL(base::BasicStringPiece<std::string>)' collect2: error: ld returned 1 exit status:app:linkNeteasenetArmeabi-v7aDebugSharedLibrary FAILEDFAILURE: Build failed with an exception.* What went wrong: Execution failed for task ':app:linkNeteasenetArmeabi-v7aDebugSharedLibrary'. > A build operation failed.Linker failed while linking libneteasenet.so.See the complete log at: file:///media/data/MyProjects/MyApplication/app/build/tmp/linkNeteasenetArmeabi-v7aDebugSharedLibrary/output.txt* Try: Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.BUILD FAILEDTotal time: 1.171 secs Linker failed while linking libneteasenet.so. 19:35:17: External task execution finished 'assembleDebug'.

這次是提示找不到符號'net::HttpResponseHeaders::EnumerateHeaderLines(unsigned int, std::string, std::string*) const''base::BasicStringPiece<std::string>::BasicStringPiece(char const*)''GURL::GURL(base::BasicStringPiece<std::string>)'。這個問題還真夠詭異。我們對相關的這些模塊,base,net和url的gn配置文件,gypi配置文件進行反復的檢查,可以百分百地確認,相關的這些文件都是有被編譯進so的。

可是為什麼能引用不到這些符號呢?那so中到底有沒有相關的這些class呢?通過GNU的binutils工具包中的readelf工具可以查看so中的所有符號,無論是函數符號,還是引用的未定義符號。而且編譯器在編譯C++文件時,符號都是會被修飾的,以便于支持函數重載等C++的一些特性。binutils工具包還提供了工具c++filt,以幫助我們將修飾后的符號,還原回編譯前的樣子。

我們利用這些工具,來檢查那些so中是否真的沒有包含未找到的那些符號:

$ readelf -s -W libbase.cr.so | grep BasicStringPiece | xargs c++filt | grep BasicStringPiecebase::BasicStringPiece<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >::BasicStringPiece(char const*) base::BasicStringPiece<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >::BasicStringPiece(char const*, unsigned int) base::BasicStringPiece<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >::BasicStringPiece(std::__1::__wrap_iter<char const*> const&, std::__1::__wrap_iter<char const*> const&) base::BasicStringPiece<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >::BasicStringPiece(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&) base::BasicStringPiece<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >::BasicStringPiece() base::BasicStringPiece<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >::BasicStringPiece(char const*) base::BasicStringPiece<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >::BasicStringPiece(char const*, unsigned int) base::BasicStringPiece<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >::BasicStringPiece(std::__1::__wrap_iter<char const*> const&, std::__1::__wrap_iter<char const*> const&) base::BasicStringPiece<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >::BasicStringPiece(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&) base::BasicStringPiece<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >::BasicStringPiece()

so還真的沒有我們的代碼中要引用的那些符號。那到底是怎么一回事呢?對比編譯我們的工程時報的錯,實際情況似乎是,在so中包含了我們需要的函數,但兩邊修飾后的符號不一致,從而導致鏈接出錯。主要是std中的符號,在so中引用的std的符號,其命名空間都增加了一級"__1"。

這似乎與stl有關。NDK可用的stl庫大體有如下的這些:

libstdc++ gabi++_static gabi++_shared stlport_static stlport_shared gnustl_static gnustl_shared c++_static c++_shared

逐個地對這些標準庫進行嘗試。除了我們前面配置的gnustl_static,上面列出的前面的5種,甚至都找不到頭文件<atomic>,gnustl_shared報出了與gnustl_static相同的問題。這就只剩下c++_static和c++_shared可選了。

我們首先嘗試c++_static,但依然報了錯:

20:00:36: Executing external task 'assembleDebug'... Observed package id 'build-tools;20.0.0' in inconsistent location '/home/hanpfei0306/data/dev_tools/Android/sdk/build-tools/android-4.4W' (Expected '/home/hanpfei0306/data/dev_tools/Android/sdk/build-tools/20.0.0') Incremental java compilation is an incubating feature. :app:compileNeteasenetArmeabi-v7aDebugSharedLibraryNeteasenetMainCpp /media/data/MyProjects/MyApplication/app/src/main/jni/src/NetJni.cpp:56: error: undefined reference to 'net::HttpResponseHeaders::EnumerateHeaderLines(unsigned int*, std::__ndk1::basic_string<char, std::__ndk1::char_traits<char>, std::__ndk1::allocator<char> >*, std::__ndk1::basic_string<char, std::__ndk1::char_traits<char>, std::__ndk1::allocator<char> >*) const' /media/data/MyProjects/MyApplication/app/src/main/jni/src/NetJni.cpp:140: error: undefined reference to 'base::BasicStringPiece<std::__ndk1::basic_string<char, std::__ndk1::char_traits<char>, std::__ndk1::allocator<char> > >::BasicStringPiece(char const*)' /media/data/MyProjects/MyApplication/app/src/main/jni/src/NetJni.cpp:140: error: undefined reference to 'GURL::GURL(base::BasicStringPiece<std::__ndk1::basic_string<char, std::__ndk1::char_traits<char>, std::__ndk1::allocator<char> > >)' collect2: error: ld returned 1 exit status:app:linkNeteasenetArmeabi-v7aDebugSharedLibrary FAILEDFAILURE: Build failed with an exception.* What went wrong: Execution failed for task ':app:linkNeteasenetArmeabi-v7aDebugSharedLibrary'. > A build operation failed.Linker failed while linking libneteasenet.so.See the complete log at: file:///media/data/MyProjects/MyApplication/app/build/tmp/linkNeteasenetArmeabi-v7aDebugSharedLibrary/output.txt* Try: Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.BUILD FAILEDTotal time: 4.385 secs Linker failed while linking libneteasenet.so. 20:00:41: External task execution finished 'assembleDebug'.

情況發生了變化。盡管依然報了undefined reference to的error,但這次引用不到的符號卻已經與我們在so中抓出來的那些符號非常接近了。c++_static和c++_shared是LLVM libc++ runtime,編譯我們的JNI時使用的這個STL的實現似乎與編譯chromium代碼時使用的那個不太一樣,但無疑編譯chromium時使用的是LLVM libc++ runtime。

我們隨便打開一個std的頭文件來一窺究竟,比如聲明std::string的頭文件android-ndk-r12b/sources/cxx-stl/llvm-libc++/libcxx/include/iosfwd,我們注意到了如下的這幾行:

_LIBCPP_BEGIN_NAMESPACE_STD...... _LIBCPP_END_NAMESPACE_STD

這個宏的定義在android-ndk-r12b/sources/cxx-stl/llvm-libc++/libcxx/include/__config:

#define _LIBCPP_ABI_VERSION 1#define _LIBCPP_CONCAT1(_LIBCPP_X,_LIBCPP_Y) _LIBCPP_X##_LIBCPP_Y #define _LIBCPP_CONCAT(_LIBCPP_X,_LIBCPP_Y) _LIBCPP_CONCAT1(_LIBCPP_X,_LIBCPP_Y)#define _LIBCPP_NAMESPACE _LIBCPP_CONCAT(__ndk,_LIBCPP_ABI_VERSION)...... #define _LIBCPP_BEGIN_NAMESPACE_STD namespace std { namespace _LIBCPP_NAMESPACE { #define _LIBCPP_END_NAMESPACE_STD } }

由此我們終于揭開了引用的符號,中間插入的那一級命名空間__ndk1的秘密。這是LLVM libc++ runtime加的。

但編譯出來的so中的符號又是怎么回事呢?chromium的代碼庫中,有完整的構建工具鏈,包括android的NDK和SDK,它們位于chromium/src/third_party/android_tools。我們打開文件chromium/src/third_party/android_tools/ndk/sources/cxx-stl/llvm-libc++/libcxx/include/__config,可以看到如下這樣的宏定義:

#define _LIBCPP_ABI_VERSION 1#define _LIBCPP_CONCAT1(_LIBCPP_X,_LIBCPP_Y) _LIBCPP_X##_LIBCPP_Y #define _LIBCPP_CONCAT(_LIBCPP_X,_LIBCPP_Y) _LIBCPP_CONCAT1(_LIBCPP_X,_LIBCPP_Y)#define _LIBCPP_NAMESPACE _LIBCPP_CONCAT(__,_LIBCPP_ABI_VERSION)

至此,這個鏈接過程中符號找不到的問題終于被厘清——chromium中的NDK不是標準NDK。

這樣的話解法也就顯而易見了,編譯我們的工程時,stl用c++_static,同時定制編譯chromium所用的NDK。

采用標準NDK編譯chromium net

為了解決編譯chromium時所用的NDK與編譯我們的工程時所用的NDK不一致,導致的鏈接錯誤,我們需要定制編譯chromium時所用的NDK。這需要重新對chromium的構建進行配置,并再次編譯chromium net。首先需要修改out/Default/args.gn,修改后的樣子如下:

target_os = "android" target_cpu = "arm" # (default) is_debug = true # (default)# Other args you may want to set: is_component_build = true is_clang = true symbol_level = 1 # Faster build with fewer symbols. -g1 rather than -g2 enable_incremental_javac = true # Much faster; experimental android_ndk_root = "~/data/dev_tools/Android/android-ndk-r12b"

然后,通過如下的命令,再次編譯chromium net。但出錯了:

$ gn gen out/Default/ Generating files... Done. Wrote 11150 targets from 881 files in 2166ms $ ninja -C out/Default/ net ninja: Entering directory `out/Default/' ninja: error: '../../../../../../home/hanpfei0306/data/dev_tools/Android/android-ndk-r12b/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/lib/gcc/arm-linux-androideabi/4.9/libgcc.a', needed by 'obj/base/third_party/dynamic_annotations/libdynamic_annotations.a', missing and no known rule to make it

這次是找不到ndk的一個文件android-ndk-r12b/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/lib/gcc/arm-linux-androideabi/4.9/libgcc.a。我們發現android-ndk-r12b/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/lib/gcc/arm-linux-androideabi/4.9目錄不存在,但是android-ndk-r12b/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/lib/gcc/arm-linux-androideabi/4.9.x是存在的,我們直接將4.9.x復制到4.9。

再次編譯,在鏈接生成libbase.cr.so時,出錯了:

$ ninja -C out/Default/ net ninja: Entering directory `out/Default/' [1349/2009] SOLINK ./libbase.cr.so FAILED: libbase.cr.so libbase.cr.so.TOC lib.unstripped/libbase.cr.so python "/media/data/chromium_android/src/build/toolchain/gcc_solink_wrapper.py" --readelf="../../../../../../home/hanpfei0306/data/dev_tools/Android/android-ndk-r12b/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin/arm-linux-androideabi-readelf" --nm="../../../../../../home/hanpfei0306/data/dev_tools/Android/android-ndk-r12b/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin/arm-linux-androideabi-nm" --strip=../../../../../../home/hanpfei0306/data/dev_tools/Android/android-ndk-r12b/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin/arm-linux-androideabi-strip --sofile="./lib.unstripped/libbase.cr.so" --tocfile="./libbase.cr.so.TOC" --output="./libbase.cr.so" -- ../../third_party/llvm-build/Release+Asserts/bin/clang++ -shared -Wl,--fatal-warnings -fPIC -Wl,-z,noexecstack -Wl,-z,now -Wl,-z,relro -Wl,-z,defs -fuse-ld=gold --gcc-toolchain=../../../../../../home/hanpfei0306/data/dev_tools/Android/android-ndk-r12b/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64 -Wl,--icf=all -Wl,--build-id=sha1 -Wl,--no-undefined -Wl,--exclude-libs=libgcc.a -Wl,--exclude-libs=libc++_static.a -Wl,--exclude-libs=libvpx_assembly_arm.a --target=arm-linux-androideabi -Wl,--warn-shared-textrel -Wl,-O1 -Wl,--as-needed -nostdlib -Wl,--warn-shared-textrel --sysroot=../../../../../../home/hanpfei0306/data/dev_tools/Android/android-ndk-r12b/platforms/android-16/arch-arm -Wl,-wrap,calloc -Wl,-wrap,free -Wl,-wrap,malloc -Wl,-wrap,memalign -Wl,-wrap,posix_memalign -Wl,-wrap,pvalloc -Wl,-wrap,realloc -Wl,-wrap,valloc -L/home/hanpfei0306/data/dev_tools/Android/android-ndk-r12b/sources/cxx-stl/llvm-libc++/libs/armeabi-v7a -o "./lib.unstripped/libbase.cr.so" -Wl,-soname="libbase.cr.so" @"./libbase.cr.so.rsp" ../../base/debug/stack_trace_android.cc:39: error: undefined reference to '_Unwind_GetIP' clang: error: linker command failed with exit code 1 (use -v to see invocation) [1358/2009] CXX obj/third_party/protobuf/protobuf_lite/extension_set.o ninja: build stopped: subcommand failed.

這次提示找不到符號_Unwind_GetIP,這個符號是libunwind中的。我們還需要修改base/BUILD.gn,在為android編譯時,添加對libunwind的依賴:

if (is_android) {config("android_system_libs") {libs = [ "log", "unwind" ] # Used by logging.cc.} }

再次編譯時依然出錯了:

$ gn args out/Default/ Waiting for editor on "/media/data/chromium_android/src/out/Default/args.gn"... Generating files... Done. Wrote 11150 targets from 881 files in 2196ms $ ninja -C out/Default/ net ninja: Entering directory `out/Default/' [27/640] SOLINK ./libicuuc.cr.so FAILED: libicuuc.cr.so libicuuc.cr.so.TOC lib.unstripped/libicuuc.cr.so python "/media/data/chromium_android/src/build/toolchain/gcc_solink_wrapper.py" --readelf="../../../../../../home/hanpfei0306/data/dev_tools/Android/android-ndk-r12b/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin/arm-linux-androideabi-readelf" --nm="../../../../../../home/hanpfei0306/data/dev_tools/Android/android-ndk-r12b/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin/arm-linux-androideabi-nm" --strip=../../../../../../home/hanpfei0306/data/dev_tools/Android/android-ndk-r12b/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin/arm-linux-androideabi-strip --sofile="./lib.unstripped/libicuuc.cr.so" --tocfile="./libicuuc.cr.so.TOC" --output="./libicuuc.cr.so" -- ../../third_party/llvm-build/Release+Asserts/bin/clang++ -shared -Wl,--fatal-warnings -fPIC -Wl,-z,noexecstack -Wl,-z,now -Wl,-z,relro -Wl,-z,defs -fuse-ld=gold --gcc-toolchain=../../../../../../home/hanpfei0306/data/dev_tools/Android/android-ndk-r12b/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64 -Wl,--icf=all -Wl,--build-id=sha1 -Wl,--no-undefined -Wl,--exclude-libs=libgcc.a -Wl,--exclude-libs=libc++_static.a -Wl,--exclude-libs=libvpx_assembly_arm.a --target=arm-linux-androideabi -Wl,--warn-shared-textrel -Wl,-O1 -Wl,--as-needed -nostdlib -Wl,--warn-shared-textrel --sysroot=../../../../../../home/hanpfei0306/data/dev_tools/Android/android-ndk-r12b/platforms/android-16/arch-arm -L/home/hanpfei0306/data/dev_tools/Android/android-ndk-r12b/sources/cxx-stl/llvm-libc++/libs/armeabi-v7a -o "./lib.unstripped/libicuuc.cr.so" -Wl,-soname="libicuuc.cr.so" @"./libicuuc.cr.so.rsp" ../../third_party/icu/source/common/rbbi.cpp:324: error: undefined reference to '__cxa_bad_typeid' ../../third_party/icu/source/common/schriter.cpp:90: error: undefined reference to '__cxa_bad_typeid' ../../third_party/icu/source/common/stringtriebuilder.cpp:386: error: undefined reference to '__cxa_bad_typeid' ../../third_party/icu/source/common/uchriter.cpp:72: error: undefined reference to '__cxa_bad_typeid' clang: error: linker command failed with exit code 1 (use -v to see invocation) [36/640] CXX obj/url/url/url_util.o ninja: build stopped: subcommand failed.

這是在編譯icu時,找不到符號__cxa_bad_typeid。這需要重新配置編譯環境,更改所用的工具鏈,不能是clang,修改之后的out/Default/args.gn如下:

target_os = "android" target_cpu = "arm" # (default) is_debug = true # (default)# Other args you may want to set: is_component_build = true is_clang = false symbol_level = 1 # Faster build with fewer symbols. -g1 rather than -g2 enable_incremental_javac = true # Much faster; experimental android_ndk_root = "/home/hanpfei0306/data/dev_tools/Android/android-ndk-r12b"

重新配置chromium的構建環境,并再次編譯net。

這終于編譯好了。將編譯出來的so文件拷貝進我們的工程。再次編譯我們的工程。但依然在報錯:

21:02:17: Executing external task 'assembleDebug'... Observed package id 'build-tools;20.0.0' in inconsistent location '/home/hanpfei0306/data/dev_tools/Android/sdk/build-tools/android-4.4W' (Expected '/home/hanpfei0306/data/dev_tools/Android/sdk/build-tools/20.0.0') Incremental java compilation is an incubating feature. :app:compileNeteasenetArmeabi-v7aDebugSharedLibraryNeteasenetMainCpp :app:linkNeteasenetArmeabi-v7aDebugSharedLibrary :app:neteasenetArmeabi-v7aDebugSharedLibrary :app:stripSymbolsArmeabi-v7aDebugSharedLibrary :app:ndkBuildArmeabi-v7aDebugSharedLibrary :app:ndkBuildArmeabi-v7aDebugStaticLibrary UP-TO-DATE :app:compileNeteasenetArmeabiDebugSharedLibraryNeteasenetMainCpp /usr/local/google/buildbot/src/android/ndk-r12-release/ndk/sources/cxx-stl/llvm-libc++/libcxx/include/atomic:922: error: undefined reference to '__atomic_fetch_add_4' /usr/local/google/buildbot/src/android/ndk-r12-release/ndk/sources/cxx-stl/llvm-libc++abi/libcxxabi/src/cxa_handlers.cpp:112: error: undefined reference to '__atomic_exchange_4' /usr/local/google/buildbot/src/android/ndk-r12-release/ndk/sources/cxx-stl/llvm-libc++abi/libcxxabi/src/cxa_default_handlers.cpp:106: error: undefined reference to '__atomic_exchange_4' /usr/local/google/buildbot/src/android/ndk-r12-release/ndk/sources/cxx-stl/llvm-libc++abi/libcxxabi/src/cxa_default_handlers.cpp:117: error: undefined reference to '__atomic_exchange_4' collect2: error: ld returned 1 exit status:app:linkNeteasenetArmeabiDebugSharedLibrary FAILEDFAILURE: Build failed with an exception.* What went wrong: Execution failed for task ':app:linkNeteasenetArmeabiDebugSharedLibrary'. > A build operation failed.Linker failed while linking libneteasenet.so.See the complete log at: file:///media/data/MyProjects/MyApplication/app/build/tmp/linkNeteasenetArmeabiDebugSharedLibrary/output.txt* Try: Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.BUILD FAILEDTotal time: 6.648 secs Linker failed while linking libneteasenet.so. 21:02:24: External task execution finished 'assembleDebug'.

不過這次已經不是找不到chromium的庫中的符號了,而是標準庫中的一些符號。這需要我們修改依賴的stl為c++_shared,而不是c++_static。再次編譯,終于build pass。

編譯鏈接的標記設置

chromium中,有許多feature的開關是通過預定義宏來控制的,它的整個的編譯鏈接都有它獨特的參數。如果在編譯我們的工程時,預定義的宏與編譯chromium時預定義的宏不一致,就很容易出現兩邊的class實際的定義不一樣的問題。比如net::URLRequestContextBuilder類的定義:

private:std::string accept_language_;std::string user_agent_;// Include support for data:// requests.bool data_enabled_; #if !defined(DISABLE_FILE_SUPPORT)// Include support for file:// requests.bool file_enabled_; #endif #if !defined(DISABLE_FTP_SUPPORT)// Include support for ftp:// requests.bool ftp_enabled_; #endifbool http_cache_enabled_;bool throttling_enabled_;bool backoff_enabled_;bool sdch_enabled_;bool cookie_store_set_by_client_;scoped_refptr<base::SingleThreadTaskRunner> file_task_runner_;HttpCacheParams http_cache_params_;HttpNetworkSessionParams http_network_session_params_;base::FilePath transport_security_persister_path_;NetLog* net_log_;std::unique_ptr<HostResolver> host_resolver_;std::unique_ptr<ChannelIDService> channel_id_service_;std::unique_ptr<ProxyConfigService> proxy_config_service_;std::unique_ptr<ProxyService> proxy_service_;std::unique_ptr<NetworkDelegate> network_delegate_;std::unique_ptr<ProxyDelegate> proxy_delegate_;std::unique_ptr<CookieStore> cookie_store_; #if !defined(DISABLE_FTP_SUPPORT)std::unique_ptr<FtpTransactionFactory> ftp_transaction_factory_; #endif

會根據宏定義來確定某些字段是否存在,如ftp_enabled_等。如果兩邊的宏定義不同,則會導致兩邊對net::URLRequestContextBuilder對象的處理不同。對于定義了宏DISABLE_FTP_SUPPORT的一邊,它在為net::URLRequestContextBuilder對象分配內存空間時,將小于另一邊看到的相同類對象的內存空間大小,可想而知,在運行期該會要出現什么樣的奇怪問題了。

比如,我們在我們的工程中,定義了宏DISABLE_FTP_SUPPORT,而在編譯chromium net時沒有定義這個宏。在我們的native代碼里,在棧上創建了一個net::URLRequestContextBuilder對象,內存將由我們的工程的編譯器分配。而在運行期,分配的這塊內存會被傳遞給類的構造函數,該構造函數則是在chromium net的so中,而它對這塊內存空間的預期要大于我們的工程的編譯器分配的大小,則在初始化的過程中,難免要踩壞周圍的內存的。

為了避免這個問題,最好的方法就是將相關的這些編譯、連接,預定義宏等,在兩邊保持一致。gn工具在這個問題上也可以幫到我們,同樣是gn desc,我們需要從輸出的如下這些段中提取我們要的參數:

$ gn desc out/Default/ net ...... cflags-fno-strict-aliasing--param=ssp-buffer-size=4-fstack-protector-funwind-tables-fPIC-pipe-ffunction-sections-fno-short-enums-finline-limit=64-march=armv7-a-mfloat-abi=softfp-mthumb-mthumb-interwork-mtune=generic-armv7-a-fno-tree-sra-fno-caller-saves-mfpu=neon-Wall-Werror-Wno-psabi-Wno-unused-local-typedefs-Wno-maybe-uninitialized-Wno-missing-field-initializers-Wno-unused-parameter-Os-fdata-sections-ffunction-sections-fomit-frame-pointer-g1--sysroot=../../../../../../home/hanpfei0306/data/dev_tools/Android/android-ndk-r12b/platforms/android-16/arch-arm-fvisibility=hiddencflags_cc-fno-threadsafe-statics-fvisibility-inlines-hidden-std=gnu++11-Wno-narrowing-fno-rtti-isystem../../../../../../home/hanpfei0306/data/dev_tools/Android/android-ndk-r12b/sources/cxx-stl/llvm-libc++/libcxx/include-isystem../../../../../../home/hanpfei0306/data/dev_tools/Android/android-ndk-r12b/sources/cxx-stl/llvm-libc++abi/libcxxabi/include-isystem../../../../../../home/hanpfei0306/data/dev_tools/Android/android-ndk-r12b/sources/android/support/include-fno-exceptions......definesV8_DEPRECATION_WARNINGSENABLE_NOTIFICATIONSENABLE_BROWSER_CDMSENABLE_PRINTING=1ENABLE_BASIC_PRINTING=1ENABLE_SPELLCHECK=1USE_BROWSER_SPELLCHECKER=1USE_OPENSSL_CERTS=1NO_TCMALLOCUSE_EXTERNAL_POPUP_MENU=1ENABLE_WEBRTC=1DISABLE_NACLENABLE_SUPERVISED_USERS=1VIDEO_HOLE=1SAFE_BROWSING_DB_REMOTECHROMIUM_BUILDENABLE_MEDIA_ROUTER=1ENABLE_WEBVRFIELDTRIAL_TESTING_ENABLED_FILE_OFFSET_BITS=64ANDROIDHAVE_SYS_UIO_HANDROID_NDK_VERSION=r10e__STDC_CONSTANT_MACROS__STDC_FORMAT_MACROSCOMPONENT_BUILD__GNU_SOURCE=1_DEBUGDYNAMIC_ANNOTATIONS_ENABLED=1WTF_USE_DYNAMIC_ANNOTATIONS=1DLOPEN_KERBEROSNET_IMPLEMENTATIONUSE_KERBEROSENABLE_BUILT_IN_DNSPOSIX_AVOID_MMAPENABLE_WEBSOCKETSGOOGLE_PROTOBUF_NO_RTTIGOOGLE_PROTOBUF_NO_STATIC_INITIALIZERHAVE_PTHREADPROTOBUF_USE_DLLSBORINGSSL_SHARED_LIBRARYU_USING_ICU_NAMESPACE=0U_ENABLE_DYLOAD=0U_NOEXCEPT=ICU_UTIL_DATA_IMPL=ICU_UTIL_DATA_FILE......ldflags-Wl,--fatal-warnings-fPIC-Wl,-z,noexecstack-Wl,-z,now-Wl,-z,relro-Wl,-z,defs-fuse-ld=gold-Wl,--icf=all-Wl,--build-id=sha1-Wl,--no-undefined-Wl,--exclude-libs=libgcc.a-Wl,--exclude-libs=libc++_static.a-Wl,--exclude-libs=libvpx_assembly_arm.a-Wl,--warn-shared-textrel-Wl,-O1-Wl,--as-needed-nostdlib-Wl,--warn-shared-textrel--sysroot=../../../../../../home/hanpfei0306/data/dev_tools/Android/android-ndk-r12b/platforms/android-16/arch-arm-Wl,-wrap,calloc-Wl,-wrap,free-Wl,-wrap,malloc-Wl,-wrap,memalign-Wl,-wrap,posix_memalign-Wl,-wrap,pvalloc-Wl,-wrap,realloc-Wl,-wrap,valloc......libsc++_shared/home/hanpfei0306/data/dev_tools/Android/android-ndk-r12b/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/lib/gcc/arm-linux-androideabi/4.9/libgcc.acatomicdlmlogunwindlib_dirs/home/hanpfei0306/data/dev_tools/Android/android-ndk-r12b/sources/cxx-stl/llvm-libc++/libs/armeabi-v7a/

最終,我們的MyApplication/app/build.gradle文件將如下面這樣:

apply plugin: 'com.android.model.application'model {repositories {libs(PrebuiltLibraries) {chromium_net {headers.srcDir "src/main/jni/third_party/chromium/include"binaries.withType(SharedLibraryBinary) {sharedLibraryFile = file("src/main/jni/third_party/chromium/libs/${targetPlatform.getName()}/libnet.cr.so")}}chromium_base {headers.srcDir "src/main/jni/third_party/chromium/include"binaries.withType(SharedLibraryBinary) {sharedLibraryFile = file("src/main/jni/third_party/chromium/libs/${targetPlatform.getName()}/libbase.cr.so")}}chromium_url {headers.srcDir "src/main/jni/third_party/chromium/include"binaries.withType(SharedLibraryBinary) {sharedLibraryFile = file("src/main/jni/third_party/chromium/libs/${targetPlatform.getName()}/liburl.cr.so")}}}}android {compileSdkVersion 23buildToolsVersion "23.0.3"defaultConfig {applicationId "com.example.hanpfei0306.myapplication"minSdkVersion.apiLevel 19targetSdkVersion.apiLevel 21versionCode 1versionName "1.0"}ndk {moduleName "neteasenet"toolchain "clang"CFlags.addAll(["-fno-strict-aliasing","--param=ssp-buffer-size=4","-fstack-protector","-funwind-tables","-fPIC","-pipe","-ffunction-sections","-fno-short-enums","-finline-limit=64","-mfloat-abi=softfp","-mfpu=neon","-Os","-fdata-sections","-ffunction-sections","-fomit-frame-pointer","-g1","-fvisibility=hidden"])CFlags.addAll(['-I' + file('src/main/jni/third_party/chromium/include/'),])cppFlags.addAll(["-fno-threadsafe-statics","-fvisibility-inlines-hidden","-std=gnu++11","-Wno-narrowing","-fno-rtti",])cppFlags.addAll(["-DV8_DEPRECATION_WARNINGS","-DENABLE_NOTIFICATIONS","-DENABLE_BROWSER_CDMS","-DENABLE_PRINTING=1","-DENABLE_BASIC_PRINTING=1","-DENABLE_SPELLCHECK=1","-DUSE_BROWSER_SPELLCHECKER=1","-DUSE_OPENSSL_CERTS=1","-DNO_TCMALLOC","-DUSE_EXTERNAL_POPUP_MENU=1","-DDISABLE_NACL","-DENABLE_SUPERVISED_USERS=1","-DCHROMIUM_BUILD","-D_FILE_OFFSET_BITS=64","-DANDROID","-DHAVE_SYS_UIO_H","-D__STDC_CONSTANT_MACROS","-D__STDC_FORMAT_MACROS","-D_FORTIFY_SOURCE=2","-DCOMPONENT_BUILD","-D__GNU_SOURCE=1","-D_DEBUG","-DDYNAMIC_ANNOTATIONS_ENABLED=1","-DWTF_USE_DYNAMIC_ANNOTATIONS=1","-DDLOPEN_KERBEROS","-DNET_IMPLEMENTATION","-DUSE_KERBEROS","-DENABLE_BUILT_IN_DNS","-DPOSIX_AVOID_MMAP","-DENABLE_WEBSOCKETS","-DGOOGLE_PROTOBUF_NO_RTTI","-DGOOGLE_PROTOBUF_NO_STATIC_INITIALIZER","-DHAVE_PTHREAD","-DPROTOBUF_USE_DLLS","-DBORINGSSL_SHARED_LIBRARY","-DU_USING_ICU_NAMESPACE=0","-DU_ENABLE_DYLOAD=0",])cppFlags.addAll(['-I' + file('src/main/jni/third_party/chromium/include'), ])ldLibs.add("android")ldLibs.add("log")ldLibs.add("z")stl "c++_shared"}sources {main {java {source {srcDir "src/main/java"}}jni {source {srcDirs = ["src/main/jni",]}dependencies {library 'chromium_base' linkage 'shared'library 'chromium_url' linkage 'shared'library 'chromium_net' linkage 'shared'}}jniLibs {source {srcDirs =["src/main/jni/third_party/chromium/libs",]}}}}buildTypes {debug {ndk {abiFilters.add("armeabi")abiFilters.add("armeabi-v7a")}}release {minifyEnabled falseproguardFiles.add(file("proguard-rules.pro"))ndk {abiFilters.add("armeabi")abiFilters.add("armeabi-v7a")}}}} } dependencies {compile fileTree(dir: 'libs', include: ['*.jar'])testCompile 'junit:junit:4.12'compile 'com.android.support:appcompat-v7:23.4.0' } 超強干貨來襲 云風專訪:近40年碼齡,通宵達旦的技術人生

總結

以上是生活随笔為你收集整理的chromium net android移植的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。