使用代理下载Chromium源码&依赖工具包
说明我们目前需要使用代理才能访问Chromium开源项目,通过给开发环境配置代理可以顺利完成其源码的下载。但是如果需要编译项目,就得使用Google提供的脚本build/install-build-deps-android.sh和gclient runhooks命令完成依赖工具的下载。 本文使用的是ubuntu 14.04版本,通过设置如下环境变量来使用代理访问外网: export http_proxy=http://{username}:{pass}@{domain}:{port}/ export https_proxy=http://{username}:{pass}@{domain}:{port}/ 另外:我之前使用过桌面版ubuntu,可以图形化的配置VPN,之后便可以完全按照Google提供的方法完成下载,暂时没搞清楚VPN跟我这里使用的代理有什么不同之处。 安装depot_tools该过程很简单,按照官网顺序执行即可,我简单记录下命令,不再赘述。 mkdir chromium cd chromium git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git export PATH="$PATH:/home/tntzlx/chromium/depot_tools" 下载源码该过程很简单,按照官网顺序执行即可,不再赘述。 tntzlx@ubuntu:~/chromium$ mkdir source tntzlx@ubuntu:~/chromium$ cd source/ tntzlx@ubuntu:~/chromium/source$ fetch --nohooks android Running: gclient root Running: gclient config --spec 'solutions = [ { "url": "https://chromium.googlesource.com/chromium/src.git","managed": False,"name": "src","deps_file": ".DEPS.git","custom_deps": {},},] target_os = ["android"] ' Running: gclient sync --nohooks 经过漫长等待即可完成代码下载 依赖包下载首先执行如下命令 cd src build/install-build-deps-android.sh 执行到后面会遇到如下错误,但是不影响最后的编译,暂时没有处理 Err http://ppa.launchpad.net trusty/main Sources 404 Not Found Err http://ppa.launchpad.net trusty/main amd64 Packages 404 Not Found Err http://ppa.launchpad.net trusty/main i386 Packages 404 Not Found Fetched 3,446 kB in 13s (246 kB/s) W: Failed to fetch http://ppa.launchpad.net/djcj/mediainfo/ubuntu/dists/trusty/main/source/Sources 404 Not Found W: Failed to fetch http://ppa.launchpad.net/djcj/mediainfo/ubuntu/dists/trusty/main/binary-amd64/Packages 404 Not Found W: Failed to fetch http://ppa.launchpad.net/djcj/mediainfo/ubuntu/dists/trusty/main/binary-i386/Packages 404 Not Found E: Some index files failed to download. They have been ignored,or old ones used instead. 然后本文的重点来了。执行如下命令: gclient runhooks 执行一段时间,会成功更新一部分工具,后续遇到错误。 0> Failed to fetch file gs://chromium-android-tools/play-services/10.2.0/31843001b7ce94fbdf71f2a9db76b28548a795fa for /tmp/tmpgymXSg/LICENSE,skipping. [Err: Failure: [Errno 1] _ssl.c:510: error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed. ] Traceback (most recent call last): File "src/build/android/play_services/update.py",line 526,in <module> sys.exit(main(sys.argv[1:])) File "src/build/android/play_services/update.py",line 96,in main return args.func(args) File "src/build/android/play_services/update.py",line 191,in Download config.version_number)): File "src/build/android/play_services/update.py",line 381,in _CheckLicenseAgreement with open(expected_license_path) as license_file: IOError: [Errno 2] No such file or directory: '/tmp/tmpgymXSg/LICENSE' Error: Command '/usr/bin/python src/build/android/play_services/update.py download' returned non-zero exit status 1 in /home/tntzlx/chromium/source 可以看到build/android/play_services/update.py会触发将gs://chromium-android-tools/play-services/10.2.0/31843001b7ce94fbdf71f2a9db76b28548a795fa下载到本地/tmp/tmpgymXSg/LICENSE。 解决方案:将"gs://chromium-android-tools/play-services/10.2.0/31843001b7ce94fbdf71f2a9db76b28548a795fa"替换成"https://storage.googleapis.com/chromium-android-tools/play-services/10.2.0/31843001b7ce94fbdf71f2a9db76b28548a795fa",即通过HTTPS协议进行下载。 修改下载脚本src/build/android/play_services/update.py def Download(args): ...... license_sha1 = os.path.join(SHA1_DIRECTORY,LICENSE_FILE_NAME + '.sha1') _DownloadFromBucket(bucket_path,license_sha1,new_license,args.verbose,args.dry_run) ...... update.py首先会对比src/build/android/play_services/google_play_services_library.zip.sha1跟src/third_party/android_tools/sdk/extras/google/m2repository/google_play_services_library.zip.sha1这两个文件是否相等。如果相等,则认为不需要更新play_services库。首次下载代码完成后是没有src/third_party/android_tools/sdk/extras/google/m2repository/google_play_services_library.zip.sha1这个文件的,故这里需要进行后面的下载(这部分逻辑代码未贴出)。 _DownloadFromBucket的实现如下,其调用download_from_google_storage.download_from_google_storage完成下载: def _DownloadFromBucket(bucket_path,sha1_file,destination,verbose,is_dry_run): '''Downloads the file designated by the provided sha1 from a cloud bucket.''' download_from_google_storage.download_from_google_storage( input_filename=sha1_file,base_url=bucket_path,gsutil=_InitGsutil(is_dry_run),num_threads=1,directory=None,recursive=False,force=False,output=destination,ignore_errors=False,sha1_file=sha1_file,verbose=verbose,auto_platform=True,extract=False) 该方法在depot_tools/download_from_google_storage.py中实现: def download_from_google_storage( input_filename,base_url,gsutil,num_threads,directory,recursive,force,output,ignore_errors,auto_platform,extract): # Start up all the worker threads. ...... t = threading.Thread( target=_downloader_worker_thread,args=[thread_num,work_queue,stdout_queue,ret_codes,extract]) t.daemon = True t.start() all_threads.append(t) ...... 通过将下载任务放到一个线程中实现下载,线程的工作函数是:_downloader_worker_thread。 def _downloader_worker_thread(thread_num,q,out_q,extract,delete=True): ...... # Check if file exists. file_url = '%s/%s' % (base_url,input_sha1_sum) (code,_,err) = gsutil.check_call('ls',file_url) if code != 0: if code == 404: out_q.put('%d> File %s for %s does not exist,skipping.' % ( thread_num,file_url,output_filename)) ret_codes.put((1,'File %s for %s does not exist.' % ( file_url,output_filename))) else: # Other error,probably auth related (bad ~/.boto,etc). out_q.put('%d> Failed to fetch file %s for %s,skipping. [Err: %s]' % ( thread_num,output_filename,err)) ret_codes.put((1,'Failed to fetch file %s for %s. [Err: %s]' % ( file_url,err))) continue # Fetch the file. out_q.put('%d> Downloading %s...' % (thread_num,output_filename)) try: if delete: os.remove(output_filename) # Delete the file if it exists already. except OSError: if os.path.exists(output_filename): out_q.put('%d> Warning: deleting %s failed.' % ( thread_num,output_filename)) code,err = gsutil.check_call('cp',output_filename) if code != 0: out_q.put('%d> %s' % (thread_num,err)) ret_codes.put((code,err)) continue ...... _downloader_worker_thread使用封装类gsutil实现对google云存储的访问。上述代码中file_url代表下载的url,是gs://格式的。该方法首先采用gsutil.check_call('ls',file_url)检查目标文件是否存在,之后采用gsutil.check_call('cp',output_filename)将file_url下载到目标文件output_filename。 0> Failed to fetch file gs://chromium-android-tools/play-services/10.2.0/31843001b7ce94fbdf71f2a9db76b28548a795fa for /tmp/tmpgymXSg/LICENSE,in _CheckLicenseAgreement with open(expected_license_path) as license_file: IOError: [Errno 2] No such file or directory: '/tmp/tmpgymXSg/LICENSE' Error: Command '/usr/bin/python src/build/android/play_services/update.py download' returned non-zero exit status 1 in /home/tntzlx/chromium/source 我们知道这个函数的最终目的就是完成文件的下载,于是就采用HTTPS下载,代替gsutil.check_call。这里我们暂且认为要下载的文件一定存在于服务器上,于是直接去掉检查文件是否存在的调用gsutil.check_call('ls',file_url),单纯把gsutil.check_call('cp',output_filename)替换成HTTPS下载。 import urllib2 httpsPrefix = "https://storage.googleapis.com/" gsPrefix = "gs://" def download_gs_to_file(url,fileName): download_http_to_file(url.replace(gsPrefix,httpsPrefix),fileName) def download_http_to_file(url,fileName): proxy = urllib2.ProxyHandler({'http': 'http://{username}:{password}@{domain}:{port}/','https': 'http://{username}:{password}@{domain}:{port}/'} ) auth = urllib2.HTTPBasicAuthHandler() opener = urllib2.build_opener(proxy,auth,urllib2.HTTPHandler) urllib2.install_opener(opener) response = urllib2.urlopen(url) CHUNK = 16 * 1024 with open(fileName,'wb') as f: while True: chunk = response.read(CHUNK) if not chunk: break f.write(chunk) 该下载器是通过urllib2模块实现的,注意我们需要使用代理,所以需要给urllib2设置代理服务: proxy = urllib2.ProxyHandler({'http': 'http://{username}:{password}@{domain}:{port}/','https': 'http://{username}:{password}@{domain}:{port}/'} ) 另外,当进行大文件下载时urllib2.urlopen.read方法不能一次读完,所以设置一个CHUNK,每次读取16K的数据,写入到目的文件中。 def _downloader_worker_thread(thread_num,delete=True): ...... file_url = '%s/%s' % (base_url,input_sha1_sum) # Fetch the file. out_q.put('%d> Downloading %s...' % (thread_num,output_filename)) download_helper.download_gs_to_file(file_url,output_filename) ...... 即可完成下载。 elif sys.platform != 'win32': # On non-Windows platforms,key off of the custom header # "x-goog-meta-executable". code,out,_ = gsutil.check_call('stat',file_url) if code != 0: out_q.put('%d> %s' % (thread_num,err)) ret_codes.put((code,err)) elif re.search(r'executable:s*1',out): st = os.stat(output_filename) os.chmod(output_filename,st.st_mode | stat.S_IEXEC) 意思是在非win32平台上面,检查下载的文件如果是可执行文件,就加上可执行权限。这里依赖gsutil.check_call('stat',file_url)的第二个返回值来判断是否是可执行文件,我这里偷个懒,暂时给所有下载的文件全部加上可执行权限则修改如下: elif sys.platform != 'win32': st = os.stat(output_filename) os.chmod(output_filename,st.st_mode | stat.S_IEXEC) 再次执行gclient runhooks即可完成下载 编译编译生成ninja文件gn gen --args='target_os="android"' out/Default 启动正式编译ninja -C out/Default chrome_public_apk 编译报错信息如下: Exception in thread "main" java.lang.UnsupportedClassVersionError: com/android/tools/lint/Main : Unsupported major.minor version 52.0 at java.lang.ClassLoader.defineClass1(Native Method) at java.lang.ClassLoader.defineClass(ClassLoader.java:803) at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142) at java.net.URLClassLoader.defineClass(URLClassLoader.java:442) at java.net.URLClassLoader.access$100(URLClassLoader.java:64) at java.net.URLClassLoader$1.run(URLClassLoader.java:354) at java.net.URLClassLoader$1.run(URLClassLoader.java:348) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(URLClassLoader.java:347) at java.lang.ClassLoader.loadClass(ClassLoader.java:425) at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308) at java.lang.ClassLoader.loadClass(ClassLoader.java:358) at sun.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:482) 根据"Unsupported major.minor version 52.0"得知,这里需要安装jdk1.8。我的单板是jdk1.7.0版本。 export JAVA_HOME=/home/java/jdk1.8.0_111 export PATH=${JAVA_HOME}/bin:$PATH 注意这里不要有下面的环境变量,否则会有报错信息。 export CLASSPATH=${JAVA_HOME}/lib tntzlx@ubuntu:~$ java -version java version "1.8.0_111" Java(TM) SE Runtime Environment (build 1.8.0_111-b14) Java HotSpot(TM) 64-Bit Server VM (build 25.111-b14,mixed mode) 说明修改成功。 此时需要删除out/Defualt目录然后 gn gen --args='target_os="android"' out/Default ninja -C out/Default chrome_public_apk 即可完成编译。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |