编译rk3399板子android10系统(ubuntu22.4)

  1. 前提条件
    编译主机内存至少 12G,交换内存 10G(swapfile),磁盘空间 150G

  2. 解压 android10
    cat rk_android_10_sdk.tar.gz* | tar xzvf

  3. 进入解压根目录
    cd rk_android_10_sdk

  4. 切换终端
    exec bash
    注意:zsh 会有问题

  5. 安装 openjdk8

  6. 安装 python2.7
    sudo apt install python2.7

  7. 安装基础库

1
2
3
sudo apt-get install git-core gnupg flex bison gperf build-essential zip curl zlib1g-dev gcc-multilib g++-multilib libc6-dev-i386 lib32ncurses5-dev x11proto-core-dev libx11-dev lib32z-dev ccache libgl1-mesa-dev libxml2-utils xsltproc unzip libssl-dev gawk liblz4-tool

sudo apt-get install libncurses5 libncurses5:i386
  1. 执行 sh javaenv.sh

  2. 执行 source build/envsetup.sh

  3. 执行 lunch
    出现菜单中,选择 6 rk3399_Android10-userdebug

  4. 如果修改 framework,需要
    make api-stubs-docs-update-current-api

  5. 执行 ./build.sh -UKAu

常见问题

  1. GLIBCXX_3.4.21 not defined in file libstdc++.so.6 with link time reference
1
2
3
4
sudo add-apt-repository ppa:ubuntu-toolchain-r/test
sudo apt-get update
sudo apt-get install gcc-5
sudo apt-get upgrade libstdc++6

android多路摄像头

原生 Android-Camera 类打开一个摄像头没有问题,打开多个会在 open()的时候报错。

注意原生 camera 要在 surface 之后在 open,否则会报错。也就是说不要直接在 oncreate 里 open。(相机 Open 前要设置 surface ,这个 surface 就是底层用来渲染预览画面的,如果 surface 都没有 create ,底层将无法渲染,我想这就是为什么 open 不了的原因吧)参考:https://bbs.csdn.net/topics/390940480

理论上,好像原生 camera 最大支持打开两个摄像头,可以参考这个代码去实现:

https://blog.csdn.net/a87636764/article/details/54645350

当然也可以看下面这个代码(比较全):

https://blog.csdn.net/CrossFile_TMS/article/details/75258570

但实际打开第二个我就报错了,报错内容:

W/CameraBase: An error occurred while connecting to camera: 1

java.lang.RuntimeException: Fail to connect to camera service

试了很多次都不行,果断放弃了原生 Camera 的思路,转向了 UVC 的方向:(下面详细写了,先膜拜一下 orz)

可以看下这个大哥的实现:https://blog.csdn.net/yyfd2013/article/details/85321175

UVCCamera 项目在 open 位置又报错了:解决 UVCCamera 项目报错:could not open camera:err=-1

参考地址:https://www.jianshu.com/p/21e95f2f1206

———————————— 我是分界线 ————————————

我去,总算搞出来了,看了一天的源码,调了一天的 bug。。。。。。

效果图如下:

主要参考了下面的项目:

UVC-Github 项目源码地址:https://github.com/saki4510t/UVCCamera

然后能搜到的是下面这两个博客:

单摄像头 github:https://github.com/jiangdongguo/AndroidUSBCamera

单摄像头 CSDN:https://blog.csdn.net/andrexpert/article/details/78324181


多路摄像头 github:https://github.com/yyfd2013zy/UvcCameraDemo

多路摄像头 CSDN:https://blog.csdn.net/yyfd2013/article/details/85321175


然后这篇文章是解析了代码,但我还是希望小伙伴们能自己去看源码,自己去消化,别人的始终不是自己的:

https://www.jianshu.com/p/9108ddfd0a0d

其中,学习的话我更偏向于多路摄像头那个项目,他用的是源码导入;而单摄像头的项目是作者自己封装了,并且我的直观感受是和源项目结构差不多,这样一封装层级结构更多了,查找源码找 bug 太复杂了。。。不过单摄像头的项目功能封装的比较多一些。

我的需求是多路摄像头的可视化 + 拍照,并且是 IOT 设备,所以倾向于多路摄像头项目。

没有不经历汗水就能拿到奖的人,资料和学习路线我都放上面了,剩下的坑要自己去趟了!

———————————— 我还是分界线 ————————————

环境:rk3288 5.1 海康摄像头


填坑之路:

首先像这么复杂的项目导入肯定是编译不过。。。一定要看清楚原博主写的经验:

传送门:https://blog.csdn.net/momo0853/article/details/73898066 看了,和官网一样,墙内用户放心下。

项目配置好 NDK 路径(是项目,别把 android studio 改了。。),clean 一下应该就没问题了。

项目跑起来之后,你会发现。。。是黑屏的。。。(一般是)

这个只能说自己的硬件,自己写日志慢慢调试吧,不同的摄像头和主板肯定不一样。项目的核心关键类是:UVCCamera

问题基本出现在下面几个方面:

1.分辨率。看源码,默认分辨率是 640*480,要看你的摄像头支不支持,不支持的话会打开成功,但是黑屏。

2.首选 FRAME_FORMAT_MJPEG,可以都换成这个试一试,如果不行,再换 FRAME_FORMAT_YUYV。我是全部 FRAME_FORMAT_MJPEG 就可以了。

3.因为各种原因导致的 open 错误,可以看英文解释:

github:https://github.com/worlfChina/UVCCameraDemo

下载后请更换项目 NDK 为您本地 r14 版本。

android源码打开日志开关

android 系统中日志及对应的等级大小为:
VERBOSE < DEBUG < INFO < WARN < ERROR

android 底层源码通过宏开关控制相应等级的日志输出。
经常在源码看到这个宏的定义
#define LOG_NDEBUG 0

如果宏被注释掉,那么只输出DEBUG及以上的日志,如果要输出全部日志,去掉该条宏定义的注释即可。

android系统预装App2

目前 5.0 之后项目预置方式通用步骤为:

建立 apk 文件夹;
置目标 apk 到该文件夹下;
解压缩 apk 查看是否包含 lib/文件夹(apk 项目是否包含 lib 库文件);
在该文件夹下编写 Android.mk 脚本 ;

理论上 apk 文件夹可以建立在项目内任意目录,编译系统会自动搜索并根据其内 Android.mk (编译脚本) 来进行编译。
编译系统采用的是递归搜索,在搜索到父文件目录的 Android.mk 脚本后递归便被终止。因此一般可以将需要预置的 apk 文件夹放到一个总文件夹内,并在该文件夹根目录另外写一个 Android.mk (管理脚本) ,以便对所有预置 apk 进行管理。对于 管理脚本 的编写将在文末解释。预置目录如下例:

Apps/
-/Android.mk 管理脚本
-/Test1
—-/Android.mk 编译脚本
—-/Test1.apk
—-/lib/_
-/Test2
—-/Android.mk 编译脚本
—-/Test2.apk
—-/lib/_

编译脚本 如下例:

LOCALPATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := Test
LOCAL_MODULE_CLASS := APPS
LOCAL_MODULE_TAGS := optional
LOCAL_BUILT_MODULE_STEM := package.apk
LOCAL_MODULE_SUFFIX := $(COMMON_ANDROID_PACKAGE_SUFFIX)
LOCAL_CERTIFICATE := PRESIGNED
LOCAL_SRC_FILES := Test
*.apk

include $(BUILD_PREBUILT)1234567891011

其中,LOCALMODULE := Test 表示了一个预置的 apk 在编译中的唯一标识,同时编译后该 apk 会以此命名;LOCAL_SRC_FILES := Test_.apk 表示了当前要预置的 apk 的文件名,”Test__.apk”匹配任意以”Test_”开头的 apk 文件。

对于 apk 预置路径,在 Android.mk 中可以通过以下方式指名:

a) 默认预置 apk 到 system/app/目录(普通系统 apk,不可卸载),如前文 Android.mk 脚本编写之后即可;
b) 预置 apk 到 system/priv-app/目录(系统核心 apk,不可卸载),在前文 Android.mk 脚本中添加并配置变量:

LOCAL_PRIVILEGED_MODULE := true1

c) 预置 apk 到 data/app/目录并且卸载后不需要再会恢复,在前文 Android.mk 脚本中配置变量:

LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)1

d) 预置 apk 到 data/app/目录并且卸载后恢复出厂可以恢复,在前文 Android.mk 简本中配置变量:

LOCAL_MODULE_PATH := $(TARGET_OUT)/vendor/operator/app1

对于包含 lib 库文件的 apk,还需要根据预置目标路径,在 mk 脚本中作不同的处理:

情况一:对于预置到 data/app/目录下的 apk,包括可恢复和不可恢复(即上一段 c) 和 d)), 一般 lib 库文件可以不用手动添加,apk 在首次运行时,会自动将自身的 lib 库抽取安装到自身的根目录;
情况二:对于预置到 system/app/ 和 system/priv-app 目录下的 apk(即上一段 a) 和 b)),因为在 android 系统中,system 分区是不允许应用执行写操作的,因此需要在 Android.mk 脚本中进行配置,手动添加 lib 库文件到编译环境,以便 lib 库文件在编译之后拷贝到对应编译后的 apk 目录下,否则 apk 执行时会因找不到 lib 库而报错;

<一>、首先根据 情况二 所述,添加 lib 库文件到编译环境

方法一 不从 apk 中解压 lib 库而直接添加

如下例,在 Android.mk 中添加并配置变量(注意路径对应):

LOCAL_PREBUILT_JNI_LIBS =
@lib/armeabi-v7a/libcryptox.so
@lib/armeabi-v7a/libfb.so 123

注意前面的 @符号,@标识符会将 apk 中的 so 抽离出来,拷贝到对应编译后的 apk 目录;

方法二 手动解压 lib 文件到当前 apk 的编译目录并添加

先解压当前 apk 内的 lib 文件夹到当前 apk 编译目录,同方法一在 Android.mk 中添加并配置变量(注意路径对应),如下例:

LOCAL_PREBUILT_JNI_LIBS =
lib/armeabi-v7a/libcryptox.so
lib/armeabi-v7a/libfb.so 123

若当前 apk 包含的 lib 库文件数量比较多时,上述代码可以通过修改为如下代码进行优化,优化的思路是用递归搜索来替代手工对 lib 库文件进行添加:

###清空临时变量 JNI_LIBS
JNI_LIBS := ###当前目录递归搜索
$(foreach FILE,$(shell find $(LOCAL_PATH)/lib/ -name *.so), $(eval JNI_LIBS += $(FILE)))
###获取搜索文件目录集(相对目录)
LOCAL_PREBUILT_JNI_LIBS := $(subst $(LOCAL_PATH),,$(JNI_LIBS))123456

<二>、然后需要注意当前 Android 环境是否符合 apk 运行条件(64 位和 32 位)并配置 apk 运行环境

之所以要配置 apk 运行环境,是因为包含 lib 库的 apk 在添加 lib 库到编译环境之后,在 Android 环境和 apk 运行条件不符的情况下,需要在编译环境中指定环境。举例说明:

目前一般的 apk 运行环境为 32 位 Android 系统环境,当在 64 位 Android 系统中预置带有 lib 库的 apk 时,手动添加 lib 库文件到编译环境后,默认情况下编译环境会在编译后 apk 目录建立 64 位的环境的 lib 库路径 /lib/arm64,虽然编译过程未报错,但之后在执行该 apk 时,会出现 apk 因找不到 lib 库而报错

因此,需要在 Android.mk 中对当前 apk 编译环境进行配置,配置的方法常见的也有两种:

<1>指定编译目标为 32 位 或 64 位

在 Android 目标中添加并配置变量:

LOCAL_MULTILIB := ###可选值 /32/64/first/both 12

不同的值含义如下:

“both”: build both 32-bit and 64-bit.
“32”: build only 32-bit.> * “64”: build only 64-bit.
“first”: build for only the first arch (32-bit in 32-bit devices and 64-bit in 64-bit devices).
“”: the default; the build system decides what arch to build based on the module class and other LOCAL_ variables, such as LOCAL_MODULE_TARGET_ARCH, LOCAL_32_BIT_ONLY, etc.

此处,default 值会根据当前已有的其他相关值方式来进行编译

<2>指定目标 lib 库的 类型
在 Android.mk 中添加并配置变量:

LOCAL_MODULE_TARGET_ARCH := ###可选值 arm/arm x86/arm6412

此处, LOCAL_MODULE_TARGET_ARCH 的值只能是当前编译环境所支持的类型,如果需要配置当前系统不支持类型,则需要配置如下另一个变量

LOCAL_MODULE_UNSUPPORTED_TARGET_ARCH := ###可选值 arm/arm x86/arm6412

与 LOCAL_MODULE_TARGET_ARCH 相反, LOCAL_MODULE_UNSUPPORTED_TARGET_ARCH 的值只能是当前编译环境所不支持的类型,否则编译将不会生效

如下是一个完整的 Android.mk 脚本示例,其中 apk 运行环境为 32 位,系统为 64 位:

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := UCBrowser
LOCAL_MODULE_CLASS := APPS
LOCAL_MODULE_TAGS := optional
LOCAL_BUILT_MODULE_STEM := package.apk
LOCAL_MODULE_SUFFIX := $(COMMON_ANDROID_PACKAGE_SUFFIX)
LOCAL_CERTIFICATE := PRESIGNED
LOCAL_SRC_FILES := HK_UCBrowser*.apk
LOCAL_PRIVILEGED_MODULE := true
LOCAL_MULTILIB := 32
JNI_LIBS :=
$(foreach FILE,$(shell find $(LOCAL_PATH)/lib/ -name *.so), $(eval JNI_LIBS += $(FILE)))
LOCAL_PREBUILT_JNI_LIBS := $(subst $(LOCAL_PATH),,$(JNI_LIBS))
include $(BUILD_PREBUILT)123456789101112131415

最后编写管理脚本集中管理预置 apk

预置三方 apk 一般根据客户项目的不同而有所差异,因此如前文所述,可以将需要预置的 apk 文件夹放到一个总文件夹内,该文件夹可以采用与客户项目有关的命名用以区分不同客户项目预置,并在该文件夹根目录另外写一个 Android.mk (管理脚本), 这样便可以根据客户项目对预置 apk 进行管理。以下是据此更新后的预置目录,具体可以根据原理自行调整:

Customer1/
-/Android.mk 管理脚本
-/Test1
—-/Android.mk 编译脚本
—-/Test1.apk
—-/lib/_
-/Test2
—-/Android.mk 编译脚本
—-/Test2.apk
—-/lib/_
Customer2/
-/Android.mk 管理脚本
-/Test3
—-/Android.mk 编译脚本
—-/Test1.apk
—-/lib/_
-/Test4
—-/Android.mk 编译脚本
—-/Test2.apk
—-/lib/_

对于 管理脚本 的编写,如下例:

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
###此处也可以在此添加一个宏变量来控制是否执行以下代码
###if($(strip $(XXX_CUSTOMER1_APP)),yes))
SUB_ANDROID_MK := $(shell find $(LOCAL_PATH)/apps/ -name Android.mk)
$(foreach sub_mk,$(SUB_ANDROID_MK), $(eval include $(sub_mk)))
PRODUCT_PACKAGES +=
Test1
Test2
###endif12345678910

其中 $(shell find $(LOCAL_PATH)/apps/ -name Android.mk) 返回一个遍历搜索子目录 Android.mk 的路径集合,此处也可以采用手动添加指定路径的方式来控制具体预置的 apk 是否编译 :

###替换
###SUB_ANDROID_MK := $(shell find $(LOCAL_PATH)/apps/ -name Android.mk)
###$(foreach sub_mk,$(SUB_ANDROID_MK), $(eval include $(sub_mk))) ###为
include Customer1/Test1/Android.mk
include Customer1/Test2/Android.mk123456

同时,PRODUCT_PACKAGES 变量指定将哪些编译完成的 apk 打包到项目最终编译生成的 Android 系统镜像文件中,如上代码中,其值恰恰就是预置 apk 的编译脚本中定义的 LOCAL_MODULE (即编译后该 apk 的名称)的值。

原文:https://blog.csdn.net/a462533587/article/details/46380795

android系统预装App

  1. ./vendor/firefly/apps/ 目录下新建 FDeviceTest 文件夹
  2. 将 Apk 放到FDeviceTest
  3. 解压 apk,把 lib 文件夹放到 FDeviceTest 中
  4. 编写 Android.mk 文件,如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
###############################################################################
# RKDeviceTest
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := FDeviceTest
LOCAL_MODULE_CLASS := APPS
#optional 该模块所有编译版本下都编译
#user 该模块只在user编译版本下才编译
#eng 该模块只在eng编译版本下才编译
#tests 该模块只在tests编译版本下才编译
LOCAL_MODULE_TAGS := optional
#编译链接后的目标文件的文件名
LOCAL_BUILT_MODULE_STEM := package.apk
LOCAL_DEX_PREOPT := false
LOCAL_MODULE_SUFFIX := $(COMMON_ANDROID_PACKAGE_SUFFIX)
#LOCAL_PROPRIETARY_MODULE 控制生成路径到system/vendor/lib,否则就是system/lib
#设置true,则LOCAL_PRIVILEGED_MODULE 优先级高,如果设置为false 则LOCAL_MODULE_PATH优先级高
LOCAL_PRIVILEGED_MODULE := true
#testkey 普通apk,默认情况下使用,默认为使用apk自己的签名
#platform 使用平台签名
#shared 使用共享签名,该apk需要和home/contacts进行共享数据
#media 使用媒体签名,该apk是media/download系统中的一环
LOCAL_CERTIFICATE := PRESIGNED
LOCAL_OVERRIDES_PACKAGES := DeviceTest
#构建系统生成模块时所用的源文件列表
LOCAL_SRC_FILES := $(LOCAL_MODULE).apk
#LOCAL_REQUIRED_MODULES :=
ifeq ($(strip $(TARGET_ARCH)), arm)
#只适用编译第三方app,且app依赖了so库 *
LOCAL_PREBUILT_JNI_LIBS := \
lib/arm/libdrm_devicetest.so \
lib/arm/libserial_port.so \
lib/arm/libgti_android.so \
lib/arm/libgti_detect.so \
lib/arm/libopencv_java3.so \
lib/arm/librknn_api.so \
lib/arm/librknn-jni.so
else ifeq ($(strip $(TARGET_ARCH)), arm64)
LOCAL_PREBUILT_JNI_LIBS := \
lib/arm64/libdrm_devicetest.so \
lib/arm64/libserial_port.so \
lib/arm64/libgti_android.so \
lib/arm64/libgti_detect.so \
lib/arm64/libopencv_java3.so \
lib/arm64/librknn_api.so \
lib/arm64/librknn-jni.so
endif
include $(BUILD_PREBUILT)
  1. 父目录的 apps.mk 中添加应用名
1
2
3
4
5
6
PRODUCT_PACKAGES += \
FDeviceTest \
FireflyDemo \
rk_ssd_demo \
GooglePinyin \
rk_openpose_demo_rga
  1. /system/app 和 /system/priv-app 有什么区别?
    /system/priv-app 是进程可以保持始终运行,并且能拿到最多的权限;坏处是无法正常升级,因为一被 kill 马上又被拉起来,并且升级完成后,再起来的还是旧版本的 service。
    所以,我们的应用被预装到终端手机 ROM 中时,为了保活,并且尽量减少终端厂商的工作量,如果能解决升级的问题,对于终端厂商来说就只需要把应用 push 到   下就可以了。没有找到解决升级的办法,最终采用的方案往往是 push 到,系统通过一个 service(如 phone)来 bind 我们的 service,一旦 disconnect 之后再来 bind,实现保活。

android的mk文件输出日志

  1. 警告方式:
    #(warning $(param))

  2. 错误方式:
    #(error $(param))

  3. 信息方式:
    #(info $(param))

示例说明