所谓的非标准头文件就是指那些在aosp外不曾见过的文件或者一些库的用法。
这个在aosp中尤其常见,例如:
String8 argv_String;
for (int i = 0; i < argc; ++i) {
argv_String.append("\"");
argv_String.append(argv[i]);
argv_String.append("\" ");
}
ALOGV("app_process main with argv: %s", argv_String.string());
String8 的定义在 system/core/libutils/include/utils/String8.h 中,为什么不用std呢?从我看代码的了解中 看到String8照顾了UTF-8的特性, 而且其UTF-8的值不能超过0x10FFFFF,
/*
* Set the filename field to a specific value.
*
* Normalizes the filename, removing a trailing '/' if present.
*/
void setPathName(const char* name);
void setPathName(const char* name, size_t numChars);
/*
* Remove the last (file name) component, leaving just the directory
* name.
*
* "/tmp/foo/bar.c" --> "/tmp/foo"
* "/tmp" --> "" // ????? shouldn't this be "/" ???? XXX
* "bar.c" --> ""
*/
String8 getPathDir(void) const;
/*
* Return the filename extension. This is the last '.' and any number
* of characters that follow it. The '.' is included in case we
* decide to expand our definition of what constitutes an extension.
*
* "/tmp/foo/bar.c" --> ".c"
* "/tmp" --> ""
* "/tmp/foo.bar/baz" --> ""
* "foo.jpeg" --> ".jpeg"
* "foo." --> ""
*/
String8 getPathExtension(void) const;
/*
* Return the path without the extension. Rules for what constitutes
* an extension are described in the comment for getPathExtension().
*
* "/tmp/foo/bar.c" --> "/tmp/foo/bar"
*/
String8 getBasePath(void) const
...
简单摘抄了一点了,可以看出,aosp自己实现了一些有助于操作的函数,尤其对于一个涉及路径文件的字符串操作。
在aosp的gerrit中,我们知道有好几百个git repo,这如果在某一阶段需要集中精力 攻克某一个问题(局限在几个repo 中)但是不想影响其他git repo,前几次公司的做法是 直接拉一个分支,注意,这个分支是一个误导词,表面说是分支,其实是一个完整的gerrit 仓库。大 回归主线不容易。
大神想了一招,就在这几个分支上拉一个真正的分支,后台CMS专家怎么拉的分支我不知道,但是 当服务器上的分支建立完成后,可以依次执行:
你就可以看见 origin/ 下的新的分支:
* vimer_dev
zhimo-aosp-d_art
remotes/m/zhimo-aosp -> origin/zhimo-aosp
remotes/origin/android-9-dev-v50
remotes/origin/aosp/android-10.0.0_r20
remotes/origin/aosp/android-10.0.0_r25
remotes/origin/aosp/android-10.0.0_r29
remotes/origin/aosp/android-9.0.0_r20
remotes/origin/aosp/android-9.0.0_r3
remotes/origin/master
remotes/origin/zhimo-aosp
remotes/origin/zhimo-aosp-d_art
remotes/origin/zhimo-aosp-d_emu
接着:
vimer@host:~/src/aosp/art$ git branch -t art_dev origin/zhimo-aosp-d_art
分支 'art_dev' 设置为跟踪来自 'origin' 的远程分支 'zhimo-aosp-d_art'。
在方法中的修饰关键词override,表明该方法应该重写(override)基于该基类的虚方法。 什么? 虚函数不就是用来重写的吗?是的,但是重写的时候会出现很多非意料之中的疏忽,至少在 我目前看来就是这样的。我们先来看下简单的例子。
#include <iostream>
using namespace std;
class Base {
public:
virtual void func() { // user want to override this in the derived class
cout << "I am in base" << endl;
}
};
class Derived : public Base {
void func(int a){ // By mistake to put int a int argument
cout << "I am in derived class" << endl;
}
};
int main(){
Base b;
Derived d;
cout << "Compiled successfully" << endl;
// cout << "Compiled successfully"
}
我们看到在Base类中,已经使用virtual进行声明了,那么在派生类中进行重写确实是理所当然的
但是,如果我们在派生类重新实现时改变了函数签名(所谓的函数签名就是指函数的名称 参数
返回值。。。)。此类错误我们应该极力避免,但是,很遗憾的是上面的程序是可以编译通过的。
不一而足,此类暗含的 编译器难以发现的错误严重影响我们的期望值,导致一些难以发觉的错误。
幸运的是,在c++11中,我们有一个关键词”override”可以阻止这种情况发生。
...
void func(int a) override
{
cout << "I am in derived class" << endl;
}
...
出错信息为:
g++ -g over2.cpp -o over2
over2.cpp:11:8: error: ‘void Derived::func(int)’ marked ‘override’, but does not override
void func(int a) override { // By mistake to put int a int argument
^~~~
override可以帮助检查以下几个方面的问题:
virtual修饰的,这个本意就是让用户在后面重写从这篇文章的题目我们就可以得知,本篇文章并不能在全局的角度介绍art test相关的东西。 我自己在对这个熟悉起来之前,真的总结不出来因为所以然。之所以还记录下来就是,让自己熟悉的 更快一些。
这个源文件定义很多与编译执行的test.最主要的就是CommonCompilerTest:
class CommonCompilerTest : public CommonRuntimeTest {
public:
CommonCompilerTest();
~CommonCompilerTest(); // deconstructor
void MakeExecutable(ArtMethod* method, const CompiledMethod* compiled_method) // git show 815d5e5304a
REQUIRES_SHARED(Locks::mutator_lock_); // CommonCompilerDriverTest 相关
static void MakeExecutable(const void* code_start, size_t code_length);
protected:
void SetUp() override; //
void SetUpRuntimeOptions(RuntimeOptions* options) override;
Compiler::Kind GetCompilerKind() const;
void SetCompilerKind(Compiler::Kind compiler_kind);
virtual CompilerFilter::Filter GetCompilerFilter() const {
return CompilerFilter::kDefaultCompilerFilter;
}
void TearDown() override;
void CompileMethod(ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_);
void CompileDirectMethod(Handle<mirror::ClassLoader> class_loader, const char* class_name,
const char* method_name, const char* signature)
REQUIRES_SHARED(Locks::mutator_lock_);
void CompileVirtualMethod(Handle<mirror::ClassLoader> class_loader, const char* class_name,
const char* method_name, const char* signature)
REQUIRES_SHARED(Locks::mutator_lock_);
void ApplyInstructionSet();
void OverrideInstructionSetFeatures(InstructionSet instruction_set, const std::string& variant);
void ClearBootImageOption();
Compiler::Kind compiler_kind_ = Compiler::kOptimizing;
InstructionSet instruction_set_ =
(kRuntimeISA == InstructionSet::kArm) ? InstructionSet::kThumb2 : kRuntimeISA;
// Take the default set of instruction features from the build.
std::unique_ptr<const InstructionSetFeatures> instruction_set_features_
= InstructionSetFeatures::FromCppDefines();
std::unique_ptr<CompilerOptions> compiler_options_;
std::unique_ptr<VerificationResults> verification_results_;
private:
// Chunks must not move their storage after being created - use the node-based std::list.
std::list<std::vector<uint8_t>> header_code_and_maps_chunks_;
};
最近没有什么事情,要说对我生活影响最大的就是趁着端午节的间隙回到山东枣庄去见了 女友一家人,当然我是那里的常客:)
还有一件事情促使我在今日留下这篇念念碎,主要是刚才对象给我打电话说自己家的 一个哥去世了。主要是那个哥和对象家来往密切,虽然这次我回去没有和他碰面, 但是前几次我们经常还是有说有笑的,所以这样的事,对我的影响还是挺震撼的。
一句话,珍惜眼前人。
最近在和脚本干上了,没办法,概念太深的理解不上去,只能先这样了。但是,我想 是自己赶快跳过这一段时间,真的很痛苦。
aosp 中使用了大量的jni,现在我们进行一个简单的总结,对aosp中的jni有一个大概的了解。
frameworks中存在大量的上层服务,也就是aosp中上层的服务。我也不理解为什么这块如此过量的使用java,今天这个例子的目录在:
frameworks/base/media/java/android/media/MediaScanner.java. 稍微统计了一下,就这个media目录中,存在了168个
文件,可见aosp中存在大量的java代码。
从java代码入手。
public class MediaScanner implements AutoCloseable {
static {
System.loadLibrary("media_jni");
native_init();
}
private final static String TAG = "MediaScanner";
...
private native void processDirectory(String path, MediaScannerClient client);
private native boolean processFile(String path, String mimeType, MediaScannerClient client);
private static native final void native_init();
private native final void native_setup();
private native final void native_finalize();
...
file: frameworks/base/media/java/android/media/MediaScanner.java.
按照邓凡平老师的书上说,media_jni会自动加载为libmedia_jni.so(显而易见,这是由C++代码写的,也就是native代码).
native关键字表示调用native代码。
这上面的代码有两点值得注意,一个是动态加载JNI动态库,一个就是调用native函数。由下面的loadLibrary我们可知,aosp中
可能是在运行时加载JNI库,后面native下面再总结。
loadLibrary:
...
@CallerSensitive
public static void loadLibrary(String libname) {
Runtime.getRuntime().loadLibrary0(Reflection.getCallerClass(), libname);
}
...
[file: ??]奇怪,没找到这个文件定义在哪块。
native_init()是后面要解决的问题。
所谓的JNI层函数就是说,不使用JNI动态库,java调用c++代码(或者反过来说也是一样的),由java的关键词native修饰的函数
就是调用JNI层的函数。
对应上面java代码的JNI层的文件在:frameworks/base/media/jni/android_media_MediaScanner.cpp,我们把两个文件的位置对比下:
frameworks/base/media/jni/android_media_MediaScanner.cpp
frameworks/base/media/java/android/media/MediaScanner.java
看到没有,这样就很容易识别,总结一句话就是,frameworks/base下的服务,绝大多说存在java和jni目录,也就是说,java相应的JNI文件 就离自己不远,这就是为什么frameworks中大量使用java做业务开发的原因吧,需要效率或者系统操作的动作时,则使用c/c++去完成。 现在来看一下android_media_MediaScanner.cpp文件中的主要内容.
...
// This function gets a field ID, which in turn causes class initialization.
// It is called from a static block in MediaScanner, which won't run until the
// first time an instance of this class is used.
static void
android_media_MediaScanner_native_init(JNIEnv *env)
{
ALOGV("native_init");
jclass clazz = env->FindClass(kClassMediaScanner);
if (clazz == NULL) {
return;
}
fields.context = env->GetFieldID(clazz, "mNativeContext", "J");
if (fields.context == NULL) {
return;
}
}
...
static jboolean
android_media_MediaScanner_processFile(
JNIEnv *env, jobject thiz, jstring path,
jstring mimeType, jobject client)
{
// Lock already hold by processDirectory
MediaScanner *mp = getNativeScanner_l(env, thiz);
if (mp == NULL) {
jniThrowException(env, kRunTimeException, "No scanner available");
return false;
}
const char *mimeTypeStr =
(mimeType ? env->GetStringUTFChars(mimeType, NULL) : NULL);
if (mimeType && mimeTypeStr == NULL) { // Out of memory
// ReleaseStringUTFChars can be called with an exception pending.
env->ReleaseStringUTFChars(path, pathStr);
return false;
}
MyMediaScannerClient myClient(env, client);
MediaScanResult result = mp->processFile(pathStr, mimeTypeStr, myClient);
if (result == MEDIA_SCAN_RESULT_ERROR) {
ALOGE("An error occurred while scanning file '%s'.", pathStr);
}
env->ReleaseStringUTFChars(path, pathStr);
if (mimeType) {
env->ReleaseStringUTFChars(mimeType, mimeTypeStr);
}
return result != MEDIA_SCAN_RESULT_ERROR;
}
如果,这里弄不明白二者之间的联系,很好,说明这个问题很关键,提醒一下,我们要注意下cpp文件中的头文件,那里有我们 想要的答案。
来看一下JNI层函数的命名:
android_media_MediaScanner_native_init这里面有什么玄机吗?是的,目前看出来的就是,这个命名规格与java的相应方法的
全路径是一模一样的。我们注意,在frameworks/base/media/java/android/media/MediaScanner.java文件中,开头就是
package android.media; # MediaScanner.java的打包
...
public class MediaScanner implements AutoCloseable {
static {
System.loadLibrary("media_jni");
native_init();
}
...
private native boolean processFile(String path, String mimeType, MediaScannerClient client);
private static native final void native_init();
...
MediaScanner作为一个大类,其方法由native_init,如果我们把这个方法的全路径补全,不就是:
android.media.MediaScanner.native_init吗,除了最后一个下划线,其他的把下划线换成点就可以将二者联系起来,这
里面一定有相关的方法是解决这个问题的。
我们上面说的就是java世界中的JNI注册的问题。
这个简单说下就是利用java的编译工具生成一个带有签名的头文件。后面会写一篇文章做一些记录的。
//#define LOG_NDEBUG 0
#define LOG_TAG "MediaScannerJNI"
#include <utils/Log.h>
#include <utils/threads.h>
#include <media/mediascanner.h>
#include <media/stagefright/StagefrightMediaScanner.h>
#include <private/media/VideoFrame.h>
#include "jni.h"
#include <nativehelper/JNIHelp.h>
#include "android_runtime/AndroidRuntime.h"
#include "android_runtime/Log.h"
#include <android-base/macros.h>