Say hello to node-gyp

Preface

install the module with

npm i node-gyp -g

examples and references
https://github.com/nodejs/node-gyp
https://github.com/nodejs/node/tree/master/test/addons/hello-world

0. Following is a simplest example, the file tree looks like this

├── binding.gyp
├── common.gypi
├── src
│   └── greeting
│   └── cpp
│   └── binding.cpp
└── test.js

1. write our ‘makefile’, binding.gyp

The configure step looks for a binding.gyp file in the current directory to process

binding.gyp

{
"targets": [
{
"target_name": "greeting",
"sources": [ "src/greeting/cpp/binding.cpp" ],
"includes": [ "common.gypi" ]
}
]
}

it also includes another gyp file, “common.gypi”

common.gypi

{
"defines": [ "V8_DEPRECATION_WARNINGS=1" ],
'conditions': [
[ 'OS in "linux freebsd openbsd solaris android aix cloudabi"', {
'cflags': ['-Wno-cast-function-type'],
}],
],
}

Then run “node-gyp configure

2. we want an interface called hello()

'use strict';
const assert = require('assert');
//const g = require("./build/Release/greeting.node");
//or use following simplier expr
const g = require("./build/Release/greeting");
g.hello();
assert.strictEqual(g.hello(), "world");
console.log('greeting.hello() =', g.hello());

3. write the c++ impl for interface hello()

#include <node.h>
#include <v8.h>

static void helloMethod(const v8::FunctionCallbackInfo<v8::Value>& args) {
v8::Isolate* isolate = args.GetIsolate();
args.GetReturnValue().Set(
v8::String::NewFromUtf8(isolate, "world", v8::NewStringType::kNormal).ToLocalChecked()
);
}

extern "C" {

NODE_MODULE_EXPORT void NODE_MODULE_INITIALIZER(v8::Local<v8::Object> exports,
v8::Local<v8::Value> module,
v8::Local<v8::Context> context) {
NODE_SET_METHOD(exports, "hello", helloMethod);
}

} //end-of-extern-c

Then run “node-gyp build“, we get “build/Release/greeting.node”, this is the node module we need.

4. run it

node test.js

enjoy!

Make your own Android boot animation

Table of Contents

    1. What is boot animation
    1. How is the animation started
    1. How to customize boot animation
    1. Try it out

1. What is boot animation

2. How is the animation started

It’s started as an init service during boot up stage
The starter file is /system/etc/init/bootanim.rc

service bootanim /system/bin/bootanimation
class core animation
user graphics
group graphics audio
disabled
oneshot
writepid /dev/stune/top-app/tasks

‘bootanimation’ application will search for animation resources in specified order,

/product/media/bootanimation.zip
/oem/media/bootanimation.zip
/system/media/bootanimation.zip

the final choice is first match.

3. How to customize boot animation

Files in bootanimation.zip

Prerequisite
A series of animated ‘png’ files

3.1 descriptor file

Descriptor file - desc.txt

800 1280 24 --> header part
p 1 0 Part0 --> body part
p 2 0 Part1 --> body part

header part

800 1280  24
| | +---- FPS
| +--------- Height
+------------- Width

body part

p   1   0   Part0
p 2 0 Part1
| | | |
| | | +------ directory name for png files
| | +------------ number of FRAMES to delay after this part
| +---------------- iterations to play, 0 for infinite loop
+-------------------- TYPE

TYPE values:

  • ‘p’: this part will play unless interrupted by the end of the boot
  • ‘c’: this part will play to completion, no matter what

Notes about descriptor file

  • Only 1 line in boby part of desc.txt can be marked as infinite loop.
  • desc.txt should be in Linux text format, otherwise it may confuse the parser.

3.2 animation contents

Animation stages are ogranized as directories.
Each diredctory matches one line in desc.txt detail part.

Part 0 \
Part 1 \
Part 2 >-- directories full of PNG frames
... /
Part N /

Then PNG files are played alphabetically.

3.3 pack everything

Finally we should pack the descriptor and PNG files into bootanimation.zip
compression method is ‘STORE’, which means no compression.
Other compression methods include DEFLATE, BZIP2, LZMA etc, but they are NOT suitable for bootanimation.
Command:

zip ../bootanimation.zip * -0 -r

4. Try it out!

Push the generated file to the platform:

adb push bootanimation.zip /system/media/bootanimation.zip

Now let’s have a look at what we have achieved:

Enjoy!

VINTF: verified assembled manifest

verified assembled manifest

系统最终生成2个verified assembled manifest, 只在host端,而不放在target板上。包含各种fragments.

BUILT_ASSEMBLED_FRAMEWORK_MANIFEST := $(PRODUCT_OUT)/verified_assembled_framework_manifest.xml
BUILT_ASSEMBLED_VENDOR_MANIFEST := $(PRODUCT_OUT)/verified_assembled_vendor_manifest.xml

可以直接make对应的文件, 如

$ make out/target/product/<TARGET_PRODUCT>/verified_assembled_framework_manifest.xml
$ make out/target/product/<TARGET_PRODUCT>/verified_assembled_vendor_manifest.xml

vasm 包含sm + system fragments + product fragments, 用vm来检查有效性

主要步骤如下:

vasm: export PRODUCT_ENFORCE_VINTF_MANIFEST=true
vasm:
assemble_vintf \
-i $(ANDROID_PRODUCT_OUT)/system/etc/vintf/manifest.xml \
$(addprefix -i ,$(wildcard $(ANDROID_PRODUCT_OUT)/system/etc/vintf/manifest/*.xml) $(wildcard $(ANDROID_PRODUCT_OUT)/product/etc/vintf/manifest/*.xml)) \
-c $(ANDROID_PRODUCT_OUT)/vendor/etc/vintf/manifest.xml \
-o verified_assembled_framework_manifest.xml

vsvm 包含vm + vendor fragments, 用sm来检查有效性

主要步骤如下

tmpKernelInfo := $(shell mktemp -d)
.INTERMEDIATE: $(tmpKernelInfo)/kernel_configs.txt
$(tmpKernelInfo)/kernel_configs.txt:
build/make/tools/extract_kernel.py \
--input out/target/product/$(TARGET_PRODUCT)/kernel \
--output-configs $(tmpKernelInfo)/kernel_configs.txt \
--output-version $(tmpKernelInfo)/kernel_version.txt

# BUILT_ASSEMBLED_VENDOR_MANIFEST := $(PRODUCT_OUT)/verified_assembled_vendor_manifest.xml
vavm: export PRODUCT_ENFORCE_VINTF_MANIFEST=true
vavm: export VINTF_ENFORCE_NO_UNUSED_HALS=true
vavm:
vavm: $(tmpKernelInfo)/kernel_configs.txt
assemble_vintf \
--kernel $(shell cat $(tmpKernelInfo)/kernel_version.txt):$(tmpKernelInfo)/kernel_configs.txt \
-i $(ANDROID_PRODUCT_OUT)/vendor/etc/vintf/manifest.xml \
$(addprefix -i ,$(wildcard $(ANDROID_PRODUCT_OUT)/vendor/etc/vintf/manifest/*.xml)) \
-c $(ANDROID_PRODUCT_OUT)/system/etc/vintf/manifest.xml \
-o verified_assembled_vendor_manifest.xml
rm -r $(tmpKernelInfo)

VINTF - compatibility matrix

Compatibility Matrix (CM)

1. 系统共需要3个compatibility matrix文件

  • System Compatibility Matrix (hardware/interfaces/compatibility_matrices/Android.mk), 下文简称scm
  • Device Compatibility Matrix (system/libhidl/vintfdata/Android.mk), 下文简称vcm
  • Product Compatibility Matrix (hardware/interfaces/compatibility_matrices/Android.mk), 下文简称pcm

其中scm, vcm是必然要生成的,而pcm则只有在定义了DEVICE_PRODUCT_COMPATIBILITY_MATRIX_FILE之后才会生成。

scm:

该文件生成比较繁琐,需要多个步骤
首先需要生成CM的check文件:
-i hardware/interfaces/compatibility_matrices/manifest.empty.xml -o manifest.check.xml
需要生成6个实际文件

compatibility_matrix.1.xml
compatibility_matrix.2.xml
compatibility_matrix.3.xml
compatibility_matrix.4.xml
compatibility_matrix.legacy.xml
compatibility_matrix.device.xml (FCM)
前5个文件定义于hardware/interfaces/compatibility_matrices/Android.bp, 从同文件夹的同名文件加上多个版本的kernel config生成(目前看到对于Oreo是3.18, 4.4, 4.9 等, 对于Q是4.9, 4.14, 4.19等)
第6个文件FCM, 从DEVICE_FRAMEWORK_COMPATIBILITY_MATRIX_FILE或者compatibility_matrix.empty.xml生成

vcm:

额外需要的变量 REQUIRED_VNDK_VERSION, BOARD_SYSTEMSDK_VERSIONS, 生成的CM带有VDNK版本号和SYSTEMSDK版本号

pcm:

强制check文件为空, 参数增加”-c hardware/interfaces/compatibility_matrices/manifest.empty.xml”

2. 图表总结

+--------+-----------------------------------------+-------------------------------+--------------------------------------------+
|Targets | Makefile Commands |output | 源文件(input files) | |
+--------+-----------------------------------------+-------------------------------+--------------------------------------------+
|scm(fcm)| make |/system/etc/vintf/ | compatibility_matrix.empty.xml |
| |framework_compatibility_matrix.device.xml|compatibility_matrix.device.xml| or |
| | | | DEVICE_FRAMEWORK_COMPATIBILITY_MATRIX_FILE |
+--------+-----------------------------------------+-------------------------------+--------------------------------------------+
|scm(all)| make system_compatibility_matrix.xml | scm + other 5 files | 同名源文件 + 多个版本的kernel config |
+--------+-----------------------------------------+-------------------------------+--------------------------------------------+
|vcm | make device_compatibility_matrix.xml |/vendor/etc/vintf/ | device_compatibility_matrix.default.xml |
| | |compatibility_matrix.xml | or DEVICE_MATRIX_FILE |
+--------+-----------------------------------------+-------------------------------+--------------------------------------------+
|pcm | make product_compatibility_matrix.xml |/product/etc/vintf/ | DEVICE_PRODUCT_COMPATIBILITY_MATRIX_FILE |
| | |compatibility_matrix.xml | |
+--------+-----------------------------------------+-------------------------------+--------------------------------------------+

VINTF: manifest.xml

manifests

1. 系统分四个manifest.xml文件

  • System Manifest (system/libhidl/vintfdata/Android.mk)
  • Product Manifest (system/libhidl/vintfdata/Android.mk)
  • Device Manifest (build/make/target/board/Android.mk)
  • ODM Manifest (build/make/target/board/Android.mk)

其中System Manifest是必然生成的,而对于Product Manifest等非必选的manifest,都需要定义相应的源文件(input file)才能用assemble_vintf生成manifest, 比如:

$ make product_manifest.xml

如果出现

FAILED: ninja: unknown target 'product_manifest.xml'

说明没有定义PRODUCT_MANIFEST_FILES, 那么此文件不需要生成。
如果定义了PRODUCT_MANIFEST_FILES, 那么文件生成方式如下:

pm:
assemble_vintf \
-i $(PRODUCT_MANIFEST_FILES) \
-o product_etc_vintf_manifest.xml

2. 图表总结

Manifest类型 Makefile Target 生成文件 .. input files (源文件)
System Manifest make system_manifest.xml /system/etc/vintf/manifest.xml DEVICE_FRAMEWORK_MANIFEST_FILE + system/libhidl/vintfdata/manifest.xml
Product Manifest make product_manifest.xml /product/etc/vintf/manifest.xml PRODUCT_MANIFEST_FILES
Device Manifest make device_manifest.xml /vendor/etc/vintf/manifest.xml DEVICE_MANIFEST_FILE
ODM Manifest make odm_manifest.xml /odm/etc/vintf/manifest.xml ODM_MANIFEST_FILES

Linux capability tests

brief intro

man:

man capabilities

Useful package:

libcap
libcap-ng

Tools:

getcap/setcap
filecap/pscap

capabilities in Android:

  • Android O and before: Use both file cap and process cap
    example:
    05-16 09:01:48.161 2824 2824 I XX : get file cap: [vendor/bin/ampservice]
    05-16 09:01:48.162 2824 2824 I XX : vendor/bin/some_service: cap_to_text(): [= cap_sys_nice+ep]

  • Android P and after: mainly use process cap in service init config

    service mtpd /system/bin/mtpd
    class main
    socket mtpd stream 600 system system
    user vpn
    group vpn inet
    capabilities NET_ADMIN NET_RAW
    disabled
    oneshot

Please note that Android external/libcap: it’s obsolete, missing ‘cap_audit_read’ in libcap/cap_names.h

cap_t to/from cap_text

cap_from_text(): cap_text

(a). 权限操作符有三种= + -

操作符前面为capability list,如果为空,默认是all
下面两中写法等价
all=p
=p

(b). 操作符后为flags

all=pie
=表示所有cap都没有flags, 即空

举例
“all=pie cap_chown-i cap_kill-pie”
“=pe cap_chown+eip cap_wake_alarm-pie” 等价于 “=ep cap_chown+i cap_wake_alarm-ep”

(c) 合法cap_text限制约束(linux only):

assertEquals(per_state | inh_state, eff_state)

测试程序

https://github.com/cfig/linux_tools/tree/master/capability_test
可以在linux/Android环境下编译

more reading …

https://training.play-with-docker.com/security-capabilities/

Android RescueParty

RescueParty简介

检测persistent app的crash, 添加于2017年。Google对此的说明是
Utilities to help rescue the system from crash loops. Callers are expected to report boot events and persistent app crashes, and if they happen frequently enough this class will slowly escalate through several rescue operations before finally rebooting and prompting the user if they want to wipe data as a last resort.

分成5个level

level_none = 0
level_reset_settings_untrusted_defaults
level_reset_settings_untrusted_changes
level_reset_settings_trusted_defaults
level_factory_reset = 4

不同rescueLevel的处理

void executeRescueLevelInternal()
1 - level_reset_settings_untrusted_defaults
resetAllSettings(reset_mode_untrusted_defaults)
2 - level_reset_settings_untrusted_changes
resetAllSettings(reset_mode_untrusted_changes)
3 - level_reset_settings_trusted_defaults
resetAllSettings(reset_mode_trusted_defaults)
4 - level_factory_reset
RecoverySystem.rebootPromptAndWipeUserData(context, TAG)
到这里就直接重启到factory reset界面

如何禁用RescueParty

如下条件满足其一即可

  • persist.sys.enable_rescue = false
  • persist.sys.disable_rescue = true
  • Build.IS_ENG
  • Build.IS_USERDEBUG && isUsbActive() # 连上usb adb

charles抓包https

配置

  • Proxy -> Windows Proxy: uncheck
  • Help -> SSL Proxying -> Install Charles Root CA: 本机安装根证书
  • Help -> SSL Proxying -> Install Charles Root CA on a Mobile Device
    • 手机Wifi-> Manual Proxy: 设置代理
    • 手机浏览器打开https://chls.pro/ssl, 下载并安装根证书
  • Proxy -> SSL Proxying Settings:
    • Enable SSL Proxying: check
    • Location: 添加需要proxy的地址,如: githug.com:443, *.github.com:443

测试:

手机浏览器访问并登录github
URL: https://github.com/session

解密后的内容为:

utf8=%E2%9C%93&authenticity_token=tWwiY8z9B5Ap%2F8sY5tf1urH5qg1diMzqSO4L37kjIy3e8hV8l56pXtf2roNFbnopEM9eA08eRXufY%2FcXbSgeuw%3D%3D&login=ff&password=guufff&return_to=%2Fcfig

测试Android Q新功能fastbootd

测试image:

Pixel 3 (blueline), Android Q preview

测试命令:

$ fastboot -w update image-blueline-qpp2.190228.023.zip --slot b

代码走向

FlashAllTool::Flash()
DumpInfo()
CheckRequirements()
set_active("a" or "b")
DetermineSecondarySlot()
CollectImages(): 有个大表,列出了所有android的image
FlashImages(boot_images_): 先刷boot相关的image, 可以用bootloader或者fastbootd来烧
UpdateSuperPartition(): 用fastbootd来烧super分区
fb->ResizePartition(partition, "0"): Resize any logical partition to 0
FlashImages(os_images_) : #Flash OS images, resizing logical partitions as needed

Console output

--------------------------------------------
Bootloader Version...: b1c1-0.2-5260815
Baseband Version.....: g845-00020-190222-B-5330671
Serial Number........: 89UX0GRHP
--------------------------------------------
extracting android-info.txt (0 MB) to RAM...
Checking 'product' OKAY [ 0.000s]
Checking 'version-bootloader' OKAY [ 0.000s]
Checking 'version-baseband' OKAY [ 0.000s]
Setting current slot to 'b' OKAY [ 0.037s]
extracting boot.img (64 MB) to disk... took 0.315s
archive does not contain 'boot.sig'
Sending 'boot_b' (65536 KB) OKAY [ 1.723s]
Writing 'boot_b' OKAY [ 0.344s]
extracting dtbo.img (8 MB) to disk... took 0.049s
archive does not contain 'dtbo.sig'
Sending 'dtbo_b' (8192 KB) OKAY [ 0.218s]
Writing 'dtbo_b' OKAY [ 0.065s]
archive does not contain 'dt.img'
archive does not contain 'recovery.img'
extracting vbmeta.img (0 MB) to disk... took 0.000s
archive does not contain 'vbmeta.sig'
Sending 'vbmeta_b' (4 KB) OKAY [ 0.001s]
Writing 'vbmeta_b' OKAY [ 0.002s]
archive does not contain 'vbmeta_system.img'
extracting super_empty.img (0 MB) to disk... took 0.000s
Sending 'system_b' (4 KB) OKAY [ 0.001s]
Updating super partition OKAY [ 0.005s]
Resizing 'product_b' OKAY [ 0.004s]
Resizing 'system_b' OKAY [ 0.004s]
Resizing 'vendor_b' OKAY [ 0.005s]
archive does not contain 'boot_other.img'
archive does not contain 'odm.img'
extracting product.img (1823 MB) to disk... took 8.553s
archive does not contain 'product.sig'
Resizing 'product_b' OKAY [ 0.005s]
Sending sparse 'product_b' 1/4 (524284 KB) OKAY [ 13.236s]
Writing 'product_b' OKAY [ 2.353s]
Sending sparse 'product_b' 2/4 (524284 KB) OKAY [ 13.815s]
Writing 'product_b' OKAY [ 2.375s]
Sending sparse 'product_b' 3/4 (524284 KB) OKAY [ 13.804s]
Writing 'product_b' OKAY [ 2.369s]
Sending sparse 'product_b' 4/4 (294892 KB) OKAY [ 7.773s]
Writing 'product_b' OKAY [ 1.441s]
archive does not contain 'product_services.img'
extracting system.img (866 MB) to disk... took 3.936s
archive does not contain 'system.sig'
Resizing 'system_b' OKAY [ 0.004s]
Sending sparse 'system_b' 1/2 (524284 KB) OKAY [ 13.523s]
Writing 'system_b' OKAY [ 2.353s]
Sending sparse 'system_b' 2/2 (362948 KB) OKAY [ 9.562s]
Writing 'system_b' OKAY [ 1.712s]
extracting system_other.img (151 MB) to disk... took 0.537s
archive does not contain 'system.sig'
Sending 'system_a' (154848 KB) OKAY [ 4.052s]
Writing 'system_a' OKAY [ 0.760s]
extracting vendor.img (430 MB) to disk... took 1.935s
archive does not contain 'vendor.sig'
Resizing 'vendor_b' OKAY [ 0.004s]
Sending 'vendor_b' (440364 KB) OKAY [ 11.548s]
Writing 'vendor_b' OKAY [ 2.024s]
archive does not contain 'vendor_other.img'
Erasing 'userdata' OKAY [ 3.760s]
Erase successful, but not automatically formatting.
File system type raw not supported.
Erasing 'metadata' OKAY [ 0.005s]
Erase successful, but not automatically formatting.
File system type raw not supported.
Rebooting OKAY [ 0.000s]
Finished. Total time: 124.375s

Android boot up performance - systrace

We can use ‘systrace’ to analyze Android boot up performance

0. Read first

https://source.android.com/devices/tech/perf/boot-times#systrace

Following steps have been verified under Android AOSP 9.0.0_r30.

1. Enable systrace:

1.1 /system/etc/init/atrace.rc

$ adb pull /system/etc/init/atrace.rc

Change
write /sys/kernel/debug/tracing/tracing_on 0
->to
write /sys/kernel/debug/tracing/tracing_on 1

add following to atrace.rc:

on property:sys.boot_completed=1
write /d/tracing/tracing_on 0
write /d/tracing/events/ext4/enable 0
write /d/tracing/events/block/enable 0

$ adb push atrace.rc /system/etc/init/atrace.rc

1.2 /system/etc/prop.default

$ adb pull /system/etc/prop.default

change
debug.atrace.tags.enableflags=0
->to
debug.atrace.tags.enableflags=802922

$ adb push prop.default /system/etc/prop.default

1.3 add kernel command line parameters

We can modify bootloader or boot.img to append following parameters

trace_buf_size=64M trace_event=sched_wakeup,sched_switch,sched_blocked_reason,sched_cpu_hotplug

2. Fetch and analyze systrace:

$ git clone https://github.com/catapult-project/catapult.git --depth=10
$ cd catapult
$ adb pull /d/tracing/trace
$ ./trace2html trace