Android 字体是由配置好的ttf字体文件来描述的,然而在字体加载的过程中首先就是根据字符去匹配相应的ttf文件,然后在该ttf文件中依照Unicode编码查找字符形状进行描绘。
Unicode 规范规定,使用U+前缀加上一个十六进制的整数表示一个字符,比如U+0041表示大写拉丁字母A。而整个Unicode的字符集,需要U+000000到U+10FFFF的存储空间,一共使用了21bit共有17*2^16个位置。从U+000000到U+10FFFF,unicod的编码空间可以被划分为17个平面(plane),每个平面包含2^16个码位。17个平面的码位就可以表示为U+xx0000到U+xxFFFF,其中xx表示0x00-0X10,共17个平面。第一个平面称之基本多语言平面(Basic Multilingual Plane BMP),或称为第0平面。其他平面成为辅助平面(Supplement Planes),其中,BMP平面内从U+D800-U+DFFF之间的码位为永久保留不映射到Unicode字符。其中UTF-16就利用该码位来对辅助平面的字符码位进行编码,目前Unicode官方支持的编码方式有三种 UTF-8,UTF-16,UTF-32,很多地方默认是UTF-16编码格式,无论是哪种编码其对应的Unicode码是唯一的。
UTF-8的规则如下:
字节数 | 最小值 | 最大值 | Byte1 | Byte2 |
---|---|---|---|---|
1 | U+0000 | U+007F | 0xxxxxxx | - |
2 | U+7F+1=U+80 | u+07FF | 110xxxxx | 10xxxxxx |
3 | U+7FF+1=U800 | u+FFFF | 1110xxxx | 10xxxxxx |
例如:汉字的“汉”其对应的Unicode码是U+6C49,把6C49转成二进制是“0110 1100 0100 1001”大于u+07FF小于u+FFFF所以是3个字节,把上面二进制填写到对应的‘x'就得到“1110 0110 ,10 110001, 10 001001”所以“汉”对应的UTF8就是“0xE6 0xB1 0x89”
Unicode的编码空间从U+000000到U+10FFFF,共分为17个平面,每个平面范围都是U+0000到U+FFFF,而该区间内的U+D800到U+DFFF是用于代理区域(Surrogate area),这个区域的码位是永久保留不映射到Unicode字符。UTF-16就利用保留下来的0xD800-0xDFFF区段的码位来对第1平面的字符(U+10000到U+10FFFF)的码位进行编码。辅助平面中的码位,在UTF-16中被编码为32位,4个字节。
低于16位字符,每8位当作一个码元来表示UTF-16编码格式。
高于16位的字符如下:
辅助平面的码位(U+010000到U+10FFFF)减去0x10000,得到的值的范围就U+0到U+FFFFF最多占20位,
高位的10bit的值(0-0x3FF)被加上0XD800得到第一个码元,称为高位代理(high surrogate),值的范围0xD800到0xDBFF。
低位的10Bit的值(0-0x3FF)被加上0xDC00得到第二个码元,称作为低位代理(low surrogate),值的范围0xDC00到0xDFFF。
低于16位的以汉字的“汉”来举例,6C49结果为 0x6C,0X49. 高于16位的如埃及象形文字“𓅘”其Unicode码为U+13158,我们减去0x10000后得到0x3158,二进制为“0011 0001 0101 1000”
区分它的高10位跟低10位:“0000 0011 00”跟“01 0101 1000”
如果按照大端在前也就是高位在前的顺序就是 ‘0xD80C 0xDD58’,反之小端在前就是‘0xDD58 0xD80C’。
UTF-16 BE:0xD80C 0xDD58 UTF-16 LE:0xDD58 0xD80C
Android的ttf字体文件是放在system/fonts/ 目录下,而我们记录ttf的xml文件是防止在了system/etc/目录下。我们配置字体的时候可以通过 mk里的“PRODUCT_COPY_FILES”命令将对应的文件copy到相应的目录下。
修改Android字体加载的模块,代码位于graphics库下,主要是修改xml文件
// frameworks/base/graphics/java/android/graphics/Typeface.java
public static void buildSystemFallback(String xmlPath, String fontDir,
ArrayMap<String, Typeface> fontMap, ArrayMap<String, FontFamily[]> fallbackMap) {
try {
//解析fonts.xml文件把内容放到FontConfig类中@1
final FileInputStream fontsIn = new FileInputStream(xmlPath);
final FontConfig fontConfig = FontListParser.parse(fontsIn);
final HashMap<String, ByteBuffer> bufferCache = new HashMap<String, ByteBuffer>();
final FontConfig.Family[] xmlFamilies = fontConfig.getFamilies();
final ArrayMap<String, ArrayList<FontFamily>> fallbackListMap = new ArrayMap<>();
//遍历出有名字的FontFamily防止到fallbackListMap。@2
// First traverse families which have a 'name' attribute to create fallback map.
for (final FontConfig.Family xmlFamily : xmlFamilies) {
final String familyName = xmlFamily.getName();
if (familyName == null) {
continue;
}
final FontFamily family = createFontFamily(
xmlFamily.getName(), Arrays.asList(xmlFamily.getFonts()),
xmlFamily.getLanguages(), xmlFamily.getVariant(), bufferCache, fontDir);
if (family == null) {
continue;
}
final ArrayList<FontFamily> fallback = new ArrayList<>();
fallback.add(family);
fallbackListMap.put(familyName, fallback);
}
// Then, add fallback fonts to the each fallback map.@3
for (int i = 0; i < xmlFamilies.length; i++) {
final FontConfig.Family xmlFamily = xmlFamilies[i];
// The first family (usually the sans-serif family) is always placed immediately
// after the primary family in the fallback.
if (i == 0 || xmlFamily.getName() == null) {
pushFamilyToFallback(xmlFamily, fallbackListMap, bufferCache, fontDir);
}
}
// Build the font map and fallback map.@4
for (int i = 0; i < fallbackListMap.size(); i++) {
final String fallbackName = fallbackListMap.keyAt(i);
final List<FontFamily> familyList = fallbackListMap.valueAt(i);
final FontFamily[] families = familyList.toArray(new FontFamily[familyList.size()]);
fallbackMap.put(fallbackName, families);
final long[] ptrArray = new long[families.length];
for (int j = 0; j < families.length; j++) {
ptrArray[j] = families[j].mNativePtr;
}
fontMap.put(fallbackName, new Typeface(nativeCreateFromArray(
ptrArray, RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE)));
}
// Insert alias to font maps.@5
for (final FontConfig.Alias alias : fontConfig.getAliases()) {
Typeface base = fontMap.get(alias.getToName());
Typeface newFace = base;
int weight = alias.getWeight();
if (weight != 400) {
newFace = new Typeface(nativeCreateWeightAlias(base.native_instance, weight));
}
fontMap.put(alias.getName(), newFace);
}
}
fonts.xml 结构如下
<familyset version="23">
<!-- first font is default -->
<family name="sans-serif">
<font weight="100" style="normal">Roboto-Thin.ttf</font>
<font weight="100" style="italic">Roboto-ThinItalic.ttf</font>
<font weight="300" style="normal">Roboto-Light.ttf</font>
<font weight="300" style="italic">Roboto-LightItalic.ttf</font>
<font weight="400" style="normal">Roboto-Regular.ttf</font>
<font weight="400" style="italic">Roboto-Italic.ttf</font>
<font weight="500" style="normal">Roboto-Medium.ttf</font>
<font weight="500" style="italic">Roboto-MediumItalic.ttf</font>
<font weight="900" style="normal">Roboto-Black.ttf</font>
<font weight="900" style="italic">Roboto-BlackItalic.ttf</font>
<font weight="700" style="normal">Roboto-Bold.ttf</font>
<font weight="700" style="italic">Roboto-BoldItalic.ttf</font>
</family>
<!-- Note that aliases must come after the fonts they reference. -->
<alias name="verdana" to="sans-serif" />
<alias name="sans-serif-condensed-light" to="sans-serif-condensed" weight="300" />
<alias name="sans-serif-condensed-medium" to="sans-serif-condensed" weight="500" />
<family lang="und-Ethi">
<font weight="400" style="normal">NotoSansEthiopic-Regular.ttf</font>
<font weight="700" style="normal">NotoSansEthiopic-Bold.ttf</font>
<font weight="400" style="normal" fallbackFor="serif">NotoSerifEthiopic-Regular.otf</font>
<font weight="700" style="normal" fallbackFor="serif">NotoSerifEthiopic-Bold.otf</font>
</family>
数据图:
这样一来我们第二步的构建的FontFamily[]里盛放的数据顺序就有了排序:
//Typeface.java
static final Map<String, Typeface> sSystemFontMap
static final Map<String, FontFamily[]> sSystemFallbackMap
理解它两的关系就不得不从Typeface的构造说起。
///frameworks/base/graphics/java/android/graphics/Typeface.java
// don't allow clients to call this directly
private Typeface(long ni) {
if (ni == 0) {
throw new RuntimeException("native typeface cannot be made");
}
native_instance = ni;
sRegistry.registerNativeAllocation(this, native_instance);
mStyle = nativeGetStyle(ni);
mWeight = nativeGetWeight(ni);
}
private static native long nativeCreateFromTypeface(long native_instance, int style);
private static native long nativeCreateFromTypefaceWithExactStyle(
long native_instance, int weight, boolean italic);
// TODO: clean up: change List<FontVariationAxis> to FontVariationAxis[]
private static native long nativeCreateFromTypefaceWithVariation(
long native_instance, List<FontVariationAxis> axes);
private static native long nativeCreateWeightAlias(long native_instance, int weight);
private static native long nativeCreateFromArray(long[] familyArray, int weight, int italic);
上述的构造器中的参数‘long ni’ 由 native 的 Typeface.cpp 来构建的,构建的方式比较多,这就拿nativeCreateFromArray来举例。
// /frameworks/base/core/jni/android/graphics/Typeface.cpp
static const JNINativeMethod gTypefaceMethods[] = {
{ "nativeCreateFromTypeface", "(JI)J", (void*)Typeface_createFromTypeface },
{ "nativeCreateFromTypefaceWithExactStyle", "(JIZ)J",
(void*)Typeface_createFromTypefaceWithExactStyle },
{ "nativeCreateFromTypefaceWithVariation", "(JLjava/util/List;)J",
(void*)Typeface_createFromTypefaceWithVariation },
{ "nativeCreateWeightAlias", "(JI)J", (void*)Typeface_createWeightAlias },
{ "nativeGetReleaseFunc", "()J", (void*)Typeface_getReleaseFunc },
{ "nativeGetStyle", "(J)I", (void*)Typeface_getStyle },
{ "nativeGetWeight", "(J)I", (void*)Typeface_getWeight },
{ "nativeCreateFromArray", "([JII)J",
(void*)Typeface_createFromArray },
{ "nativeSetDefault", "(J)V", (void*)Typeface_setDefault },
{ "nativeGetSupportedAxes", "(J)[I", (void*)Typeface_getSupportedAxes },
};
static jlong Typeface_createFromArray(JNIEnv *env, jobject, jlongArray familyArray,
int weight, int italic) {
ScopedLongArrayRO families(env, familyArray);
std::vector<std::shared_ptr<minikin::FontFamily>> familyVec;
familyVec.reserve(families.size());
for (size_t i = 0; i < families.size(); i++) {
FontFamilyWrapper* family = reinterpret_cast<FontFamilyWrapper*>(families[i]);
familyVec.emplace_back(family->family);
}
return toJLong(Typeface::createFromFamilies(std::move(familyVec), weight, italic));
}
这个Typeface_createFromArray的参数familyArray就是FontFamily[],最后构建native层的Typeface实例,将 familyArray 传给 FontCollection 持有。
// /frameworks/minikin/include/minikin/FontCollection.h
std::vector<std::shared_ptr<FontFamily>> mFamilies;
createFromFamilies 方法是构建Typeface及其全局变量。
// /frameworks/base/libs/hwui/hwui/Typeface.h
struct ANDROID_API Typeface {
public:
std::shared_ptr<minikin::FontCollection> fFontCollection;
// resolved style actually used for rendering
minikin::FontStyle fStyle;
// style used in the API
enum Style : uint8_t { kNormal = 0, kBold = 0x01, kItalic = 0x02, kBoldItalic = 0x03 };
Style fAPIStyle;
static const Typeface* resolveDefault(const Typeface* src);
// The following three functions create new Typeface from an existing Typeface with a different
// style. There is a base weight concept which is used for calculating relative style from an
// existing Typeface.
// The createRelative method creates a new Typeface with a style relative to the base Typeface.
// For example, if the base Typeface has a base weight of 400 and the desired style is bold, the
// resulting Typeface renders the text with a weight of 700. This function doesn't change the
// base weight, so even if you create a new Typeface from the bold Typeface specifying bold on
// it again, the text is still rendered with a weight of 700.
// You can create another base weight Typeface from an existing Typeface with
// createWithDifferentBaseWeight. The Typeface created with this function renders the text with
// a specified base weight.
// The createAbsolute method creates a new Typeface ignoring the base weight.
// Here is an example:
// Typeface* base = resolveDefault(nullptr); // Usually this has a weight of 400.
// Typeface* bold = createRelative(base, Bold); // Rendered with a weight of 700.
// Typeface* bold2 = createRelative(bold, Bold); // Rendered with a weight of 700.
//
// Typeface* boldBase = createWithDifferentBaseWeight(base, 700); // With a weight of 700.
// Typeface* boldBold = createRelative(boldBase, Bold); // Rendered with a weight of 1000.
//
// Typeface* lightBase = createWithDifferentBaseWeight(base, 300); // With a weight of 300.
// Typeface* lightBold = createRelative(lightBase, Bold); // Rendered with a weight of 600.
//
// Typeface* black = createAbsolute(base, 900, false); // Rendered with a weight of 900.
static Typeface* createWithDifferentBaseWeight(Typeface* src, int baseweight);
static Typeface* createRelative(Typeface* src, Style desiredStyle);
static Typeface* createAbsolute(Typeface* base, int weight, bool italic);
static Typeface* createFromTypefaceWithVariation(
Typeface* src, const std::vector<minikin::FontVariation>& variations);
static Typeface* createFromFamilies(
std::vector<std::shared_ptr<minikin::FontFamily>>&& families, int weight, int italic);
static void setDefault(const Typeface* face);
// Sets roboto font as the default typeface for testing purpose.
static void setRobotoTypefaceForTest();
private:
// base weight in CSS-style units, 1..1000
int fBaseWeight;
};
// /frameworks/base/libs/hwui/hwui/Typeface.cpp
Typeface* Typeface::createFromFamilies(std::vector<std::shared_ptr<minikin::FontFamily>>&& families,
int weight, int italic) {
Typeface* result = new Typeface;
result->fFontCollection.reset(new minikin::FontCollection(families));
if (weight == RESOLVE_BY_FONT_TABLE || italic == RESOLVE_BY_FONT_TABLE) {
int weightFromFont;
bool italicFromFont;
const minikin::FontStyle defaultStyle;
const minikin::MinikinFont* mf = families.empty() ? nullptr
: families[0]->getClosestMatch(defaultStyle).font->typeface().get();
if (mf != nullptr) {
SkTypeface* skTypeface = reinterpret_cast<const MinikinFontSkia*>(mf)->GetSkTypeface();
const SkFontStyle& style = skTypeface->fontStyle();
weightFromFont = style.weight();
italicFromFont = style.slant() != SkFontStyle::kUpright_Slant;
} else {
// We can't obtain any information from fonts. Just use default values.
weightFromFont = SkFontStyle::kNormal_Weight;
italicFromFont = false;
}
if (weight == RESOLVE_BY_FONT_TABLE) {
weight = weightFromFont;
}
if (italic == RESOLVE_BY_FONT_TABLE) {
italic = italicFromFont ? 1 : 0;
}
}
// Sanitize the invalid value passed from public API.
if (weight < 0) {
weight = SkFontStyle::kNormal_Weight;
}
result->fBaseWeight = weight;
result->fAPIStyle = computeAPIStyle(weight, italic);
result->fStyle = computeMinikinStyle(weight, italic);
return result;
Typeface作为Paint里的一员,通过JNI的方式可以从Java层或者c++层设置到native的Paint
// frameworks\base\graphics\java\android\graphics\Paint.java
public Typeface setTypeface(Typeface typeface) {
final long typefaceNative = typeface == null ? 0 : typeface.native_instance;
nSetTypeface(mNativePaint, typefaceNative);
mTypeface = typeface;
return typeface;
}
// frameworks\base\libs\hwui\jni\Paint.cpp
static const JNINativeMethod methods[] = {
...
{"nSetTypeface","(JJ)V", (void*) PaintGlue::setTypeface},
...
}
static void setTypeface(CRITICAL_JNI_PARAMS_COMMA jlong objHandle, jlong typefaceHandle) {
Paint* paint = reinterpret_cast<Paint*>(objHandle);
paint->setAndroidTypeface(reinterpret_cast<Typeface*>(typefaceHandle));
}
void setAndroidTypeface(Typeface* typeface) { mTypeface = typeface; }
paint 与 Font 之间的链路关系如图
下面是贴出一份从应用onMeasure调用jni的接口 Paint.java 的 nGetRunAdvance() 方法,再到paint.cpp 的measureText()一直到最终找到font文件的id并通过harfbuzz_ng这个库去处理font文件本身的一份堆栈,以便后期研究使用。
#00 pc 00000000000460f4 /system/lib64/libharfbuzz_ng.so (decompose_current_character(hb_ot_shape_normalize_context_t const*, bool)+788)
#01 pc 0000000000045078 /system/lib64/libharfbuzz_ng.so (_hb_ot_shape_normalize(hb_ot_shape_plan_t const*, hb_buffer_t*, hb_font_t*)+296)
#02 pc 0000000000038a10 /system/lib64/libharfbuzz_ng.so (_hb_ot_shape+1304)
#03 pc 0000000000013ff0 /system/lib64/libharfbuzz_ng.so (hb_shape_plan_execute+144)
#04 pc 0000000000013ba0 /system/lib64/libharfbuzz_ng.so (hb_shape+80)
#05 pc 0000000000018234 /system/lib64/libminikin.so (minikin::Layout::doLayoutRun(unsigned short const*, unsigned long, unsigned long, unsigned long, bool, minikin::MinikinPaint const&, minikin::StartHyphenEd
#06 pc 00000000000153b0 /system/lib64/libminikin.so (minikin::LayoutCacheKey::doLayout(minikin::Layout*, minikin::MinikinPaint const&) const+376)
#07 pc 0000000000015078 /system/lib64/libminikin.so (void minikin::LayoutCache::getOrCreate<minikin::LayoutAppendFunctor>(minikin::U16StringPiece const&, minikin::Range const&, minikin::MinikinPaint const&, b
#08 pc 0000000000014a10 /system/lib64/libminikin.so (minikin::Layout::doLayoutWord(unsigned short const*, unsigned long, unsigned long, unsigned long, bool, minikin::MinikinPaint const&, unsigned long, miniki
#09 pc 0000000000014680 /system/lib64/libminikin.so (minikin::Layout::doLayoutRunCached(minikin::U16StringPiece const&, minikin::Range const&, bool, minikin::MinikinPaint const&, unsigned long, minikin::Start
#10 pc 00000000000192d4 /system/lib64/libminikin.so (minikin::Layout::measureText(minikin::U16StringPiece const&, minikin::Range const&, minikin::Bidi, minikin::MinikinPaint const&, minikin::StartHyphenEdit,
#11 pc 00000000000f2ac4 /system/lib64/libhwui.so (android::MinikinUtils::measureText(android::Paint const*, minikin::Bidi, android::Typeface const*, unsigned short const*, unsigned long, unsigned long, unsign
#12 pc 000000000014e52c /system/lib64/libandroid_runtime.so (android::PaintGlue::getRunAdvance___CIIIIZI_F(_JNIEnv*, _jclass*, long, _jcharArray*, int, int, int, int, unsigned char, int)+388)
#13 pc 00000000003de18c /system/framework/arm64/boot-framework.oat (offset 0x3d2000) (android.graphics.Paint.nGetRunAdvance+236)
#14 pc 00000000007f52d8 /system/framework/arm64/boot-framework.oat (offset 0x3d2000) (android.graphics.Paint.getRunAdvance+1208)
#15 pc 00000000007f4d38 /system/framework/arm64/boot-framework.oat (offset 0x3d2000) (android.graphics.Paint.getRunAdvance+328)
#16 pc 0000000000b31288 /system/framework/arm64/boot-framework.oat (offset 0x3d2000) (android.text.TextLine.getRunAdvance+760)
#17 pc 0000000000b32494 /system/framework/arm64/boot-framework.oat (offset 0x3d2000) (android.text.TextLine.handleText+372)
#18 pc 0000000000b31858 /system/framework/arm64/boot-framework.oat (offset 0x3d2000) (android.text.TextLine.handleRun+680)
#19 pc 0000000000b33278 /system/framework/arm64/boot-framework.oat (offset 0x3d2000) (android.text.TextLine.measure+216)
#20 pc 0000000000b337dc /system/framework/arm64/boot-framework.oat (offset 0x3d2000) (android.text.TextLine.metrics+60)
#21 pc 0000000000b23b28 /system/framework/arm64/boot-framework.oat (offset 0x3d2000) (android.text.Layout.measurePara+1192)
#22 pc 0000000000b21e0c /system/framework/arm64/boot-framework.oat (offset 0x3d2000) (android.text.Layout.getDesiredWidthWithLimit+140)
#23 pc 0000000000d70124 /system/framework/arm64/boot-framework.oat (offset 0x3d2000) (android.widget.TextView.onMeasure+644)
#24 pc 0000000000c7fe3c /system/framework/arm64/boot-framework.oat (offset 0x3d2000) (android.view.View.measure+956)
#25 pc 00000000006d8fc4 /system/framework/arm64/boot-framework.oat (offset 0x3d2000) (android.widget.GridLayout.measureChildrenWithMargins+1588)
#26 pc 00000000006da3ec /system/framework/arm64/boot-framework.oat (offset 0x3d2000) (android.widget.GridLayout.onMeasure+380)
#27 pc 0000000000c7fe3c /system/framework/arm64/boot-framework.oat (offset 0x3d2000) (android.view.View.measure+956)
#28 pc 0000000000d40574 /system/framework/arm64/boot-framework.oat (offset 0x3d2000) (android.view.ViewGroup.measureChildWithMargins+260)
#29 pc 0000000000dd33f4 /system/framework/arm64/boot-framework.oat (offset 0x3d2000) (android.widget.FrameLayout.onMeasure+340)
#30 pc 0000000000c7fe3c /system/framework/arm64/boot-framework.oat (offset 0x3d2000) (android.view.View.measure+956)
#31 pc 0000000000d40574 /system/framework/arm64/boot-framework.oat (offset 0x3d2000) (android.view.ViewGroup.measureChildWithMargins+260)
#32 pc 000000000073dac4 /system/framework/arm64/boot-framework.oat (offset 0x3d2000) (com.android.internal.widget.ActionBarOverlayLayout.onMeasure+1476)
#33 pc 0000000000c7fe3c /system/framework/arm64/boot-framework.oat (offset 0x3d2000) (android.view.View.measure+956)
#34 pc 0000000000d40574 /system/framework/arm64/boot-framework.oat (offset 0x3d2000) (android.view.ViewGroup.measureChildWithMargins+260)
#35 pc 0000000000dd33f4 /system/framework/arm64/boot-framework.oat (offset 0x3d2000) (android.widget.FrameLayout.onMeasure+340)
#36 pc 0000000000e0f4c4 /system/framework/arm64/boot-framework.oat (offset 0x3d2000) (com.android.internal.policy.DecorView.onMeasure+1268)
#37 pc 0000000000c7fe3c /system/framework/arm64/boot-framework.oat (offset 0x3d2000) (android.view.View.measure+956)
#38 pc 0000000000c9f2c8 /system/framework/arm64/boot-framework.oat (offset 0x3d2000) (android.view.ViewRootImpl.performMeasure+264)
#39 pc 0000000000c9de80 /system/framework/arm64/boot-framework.oat (offset 0x3d2000) (android.view.ViewRootImpl.measureHierarchy+1152)
#40 pc 0000000000c9fd88 /system/framework/arm64/boot-framework.oat (offset 0x3d2000) (android.view.ViewRootImpl.performTraversals+2456)
#41 pc 0000000000ca47f4 /system/framework/arm64/boot-framework.oat (offset 0x3d2000) (android.view.ViewRootImpl.doTraversal+196)
#42 pc 00000000008d175c /system/framework/arm64/boot-framework.oat (offset 0x3d2000) (android.content.ContextWrapper.getBasePackageName [DEDUPED]+60)
#43 pc 0000000000b7391c /system/framework/arm64/boot-framework.oat (offset 0x3d2000) (android.view.Choreographer.doCallbacks+956)
#44 pc 0000000000b7422c /system/framework/arm64/boot-framework.oat (offset 0x3d2000) (android.view.Choreographer.doFrame+1484)
#45 pc 0000000000c5d5c8 /system/framework/arm64/boot-framework.oat (offset 0x3d2000) (android.view.Choreographer$FrameDisplayEventReceiver.run+72)
#46 pc 0000000000ab363c /system/framework/arm64/boot-framework.oat (offset 0x3d2000) (android.os.Handler.dispatchMessage+76)
#47 pc 0000000000ab67a0 /system/framework/arm64/boot-framework.oat (offset 0x3d2000) (android.os.Looper.loop+1264)
#48 pc 0000000000882578 /system/framework/arm64/boot-framework.oat (offset 0x3d2000) (android.app.ActivityThread.main+664)
#49 pc 000000000055d04c /system/lib64/libart.so (art_quick_invoke_static_stub+604)
#50 pc 00000000000cf760 /system/lib64/libart.so (art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)+232)
#51 pc 00000000004633b8 /system/lib64/libart.so (art::(anonymous namespace)::InvokeWithArgArray(art::ScopedObjectAccessAlreadyRunnable const&, art::ArtMethod*, art::(anonymous namespace)::ArgArray*, art::JValue*, char const*)+104)
#52 pc 0000000000464e10 /system/lib64/libart.so (art::InvokeMethod(art::ScopedObjectAccessAlreadyRunnable const&, _jobject*, _jobject*, _jobject*, unsigned long)+1440)
#53 pc 00000000003f43b0 /system/lib64/libart.so (art::Method_invoke(_JNIEnv*, _jobject*, _jobject*, _jobjectArray*)+48)
#54 pc 00000000001206d4 /system/framework/arm64/boot.oat (offset 0x116000) (java.lang.Class.getDeclaredMethodInternal [DEDUPED]+180)
#55 pc 0000000000bed188 /system/framework/arm64/boot-framework.oat (offset 0x3d2000) (com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run+136)
#56 pc 0000000000bf4668 /system/framework/arm64/boot-framework.oat (offset 0x3d2000) (com.android.internal.os.ZygoteInit.main+3576)
#57 pc 000000000055d04c /system/lib64/libart.so (art_quick_invoke_static_stub+604)
#58 pc 00000000000cf760 /system/lib64/libart.so (art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)+232)
#59 pc 00000000004633b8 /system/lib64/libart.so (art::(anonymous namespace)::InvokeWithArgArray(art::ScopedObjectAccessAlreadyRunnable const&, art::ArtMethod*, art::(anonymous namespace)::ArgArray*, art::JValue*, char const*)+104)
#60 pc 0000000000463010 /system/lib64/libart.so (art::InvokeWithVarArgs(art::ScopedObjectAccessAlreadyRunnable const&, _jobject*, _jmethodID*, std::__va_list)+416)
#61 pc 0000000000366854 /system/lib64/libart.so (art::JNI::CallStaticVoidMethodV(_JNIEnv*, _jclass*, _jmethodID*, std::__va_list)+644)
#62 pc 00000000000b2240 /system/lib64/libandroid_runtime.so (_JNIEnv::CallStaticVoidMethod(_jclass*, _jmethodID*, ...)+120)
#63 pc 00000000000b4c78 /system/lib64/libandroid_runtime.so (android::AndroidRuntime::start(char const*, android::Vector<android::String8> const&, bool)+784)
#64 pc 00000000000021f8 /system/bin/app_process64 (main+1200)
#65 pc 00000000000ab330 /system/lib64/libc.so (__libc_init+88)
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。