2024年7月

前言

方案商定制的主板,加入了360°环视算法功能,涉及到了一些库的添加,重新制作了依赖库的镜像,镜像更新的原来的板子上。


定制的板子

在这里插入图片描述


升级接口type-c

设计接口是type-c,需要通过type-c数据线转USB连接电脑,这里开发板都是USB对USB口的线,设计有所不同。
在这里插入图片描述


升级按键方法

这里的按键与开发板的设计也不是一样的:
在这里插入图片描述

先上电,先按下面的不松,再按上面的不松,约10~15秒可以让RKDevTool识别设备。


RK刷机软件

RK刷机的软件以及驱动
在这里插入图片描述

(驱动是笔者自己开发板里面的)
在这里插入图片描述


刷机镜像

在这里插入图片描述


更新镜像


步骤一:连接板子type-c接口与电脑usb接口

在这里插入图片描述


步骤二:安装RK3588的驱动

注意:RK3588要重新打驱动:
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述


步骤三:打开RK刷机软件RKDevTool

绿色版本,不需要安装的
在这里插入图片描述

在这里插入图片描述


步骤四:选择升级固件

跟刷固件不一样,这次是升级固件:
在这里插入图片描述

在这里插入图片描述

选择升级的固件:
在这里插入图片描述


步骤五:连接设备

这里一直发现不了设备,后来解决,查看《关于 RK3588刷镜像升级镜像”没有发现设备“ 的解决方法》。
在这里插入图片描述

一只手上电,一只手在按键处,上电后约200ms按下面的按键,然后500ms后按上面的按键:
在这里插入图片描述

在这里插入图片描述

这样就行了。


步骤六:升级镜像

点击升级:
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

Ok刷机成功,自动重启了。
在这里插入图片描述

在出第一款博客园T恤时,由于
第三版
设计的星星款打样出来的实物效果过于可爱,我们做了一个艰难的决定——弃星上码,改为
废话少说,放码过来
,从而伤了一颗星——园子的闪存幸运星。

在上架后复盘时我们认识到天生可爱不是星星的错,伤星才是大错,于是我们决定将功补过,为星星重新来过,重新设计星星款T恤。

在推倒重来的设计中,面对星星挡不住的可爱,我们有一个小安排——酷过可爱,伤星不再,于是就有了今天发出来给大家预览的酷星星款设计稿预览。

欢迎大家对这个设计稿进行点评,如果觉得好看,欢迎说明分别喜欢第一款与第二款的哪一个,如果觉得不好看,欢迎吐槽。

一:背景

1. 讲故事

前些天有位朋友找到我,说他的程序每次关闭时就会自动崩溃,一直找不到原因让我帮忙看一下怎么回事,这位朋友应该是第二次找我了,分析了下 dump 还是挺经典的,拿出来给大家分享一下吧。

二:WinDbg 分析

1. 为什么会崩溃

找崩溃原因比较简单,用
!analyze -v
命令观察一下便知。


0:040> !analyze -v

CONTEXT:  (.ecxr)
eax=0afdf5dc ebx=0698ade8 ecx=00000001 edx=00000000 esi=0698ade8 edi=7eec0000
eip=7753c5af esp=0afdf5dc ebp=0afdf62c iopl=0         nv up ei pl nz na po nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000202
KERNELBASE!RaiseException+0x58:
7753c5af c9              leave
Resetting default scope

EXCEPTION_RECORD:  (.exr -1)
ExceptionAddress: 7753c5af (KERNELBASE!RaiseException+0x00000058)
   ExceptionCode: c0020001
  ExceptionFlags: 00000001
NumberParameters: 1
   Parameter[0]: 8007042b

PROCESS_NAME:  xxx.exe

从卦中数据看当前崩溃码是 c0020001,查了下码表说是
string绑定无效
,截图如下:

这看起来有点无语呀,接下来观察下线程栈。


0:040> .ecxr
eax=0afdf5dc ebx=0698ade8 ecx=00000001 edx=00000000 esi=0698ade8 edi=7eec0000
eip=7753c5af esp=0afdf5dc ebp=0afdf62c iopl=0         nv up ei pl nz na po nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000202
KERNELBASE!RaiseException+0x58:
7753c5af c9              leave

0:040> k
  *** Stack trace for last set context - .thread/.cxr resets it
 # ChildEBP RetAddr      
00 0afdf62c 70e75e0b     KERNELBASE!RaiseException+0x58
01 0afdf648 70f63bf5     clr!COMPlusThrowBoot+0x1a
02 0afdf654 70b6f1da     clr!UMThunkStubRareDisableWorker+0x25
03 0afdf67c 77a9571e     clr!UMThunkStubRareDisable+0x9
04 0afdf6bc 77a80f0b     ntdll!RtlpTpTimerCallback+0x7a
05 0afdf6e0 77a809b1     ntdll!TppTimerpExecuteCallback+0x10f
06 0afdf830 75c4344d     ntdll!TppWorkerThread+0x562
07 0afdf83c 77a69802     kernel32!BaseThreadInitThunk+0xe
08 0afdf87c 77a697d5     ntdll!__RtlUserThreadStart+0x70
09 0afdf894 00000000     ntdll!_RtlUserThreadStart+0x1b

从卦中的线程栈来看,这里利用了
Windows线程池
的timer回调,回到 clr 之后主动抛了一个异常。

2. 为什么会主动抛异常

要想知道这个答案需要分析下clr 的源码,简化后如下:


// Disable from a place that is calling into managed code via a UMEntryThunk.
extern "C" VOID __stdcall UMThunkStubRareDisableWorker(Thread * pThread, UMEntryThunk * pUMEntryThunk, Frame * pFrame)
{
    // Check for ShutDown scenario.  This happens only when we have initiated shutdown 
    // and someone is trying to call in after the CLR is suspended.  In that case, we
    // must either raise an unmanaged exception or return an HRESULT, depending on the
    // expectations of our caller.
    if (!CanRunManagedCode())
    {
        pThread->m_fPreemptiveGCDisabled = 0;
        COMPlusThrowBoot(E_PROCESS_SHUTDOWN_REENTRY);
    }
}

BOOL CanRunManagedCode(BOOL fCannotRunIsUserError, HINSTANCE hInst)
{
    // If we are shutting down the runtime, then we cannot run code.
    if (g_fForbidEnterEE == TRUE)
        return FALSE;

    // If we are finaling live objects or processing ExitProcess event,
    // we can not allow managed method to run unless the current thread
    // is the finalizer thread
    if ((g_fEEShutDown & ShutDown_Finalize2) && !GCHeap::GetGCHeap()->IsCurrentThreadFinalizer())
        return FALSE;

    // If pre-loaded objects are not present, then no way.
    if (g_pPreallocatedOutOfMemoryException == NULL)
        return FALSE;

    return TRUE;
}

根据上面的源码,应该就是
CanRunManagedCode()
函数返回false 导致的,那这个函数真的返回 false 吗?可以用 Windbg 验证下g_fForbidEnterEE 这个变量。


0:040> dp clr!g_fForbidEnterEE L1
712a2684  00000001

无语了,这个变量为true表示当前的CLR处于关闭状态,应该是主线程调用了 Exit 方法,用 windbg 可以简单验证下。


0:000> k
00 0028d3b0 77549cd4     ntdll!NtQueryAttributesFile+0x12
01 0028d3b0 70bf560b     KERNELBASE!GetFileAttributesW+0x71
02 0028d3c8 710602a5     clr!CheckFileExistence+0x1a
...
39 0028ebc0 70d2684b     clr!WaitForEndOfShutdown_OneIteration+0x81
3a 0028ebc8 70d300e2     clr!WaitForEndOfShutdown+0x1b
3b 0028ec08 70d1329e     clr!EEShutDown+0xad
3c 0028ec14 70d132fb     clr!HandleExitProcessHelper+0x4d
3d 0028ec70 70d2ff99     clr!EEPolicy::HandleExitProcess+0x50
3e 0028ec70 7115af3b     clr!ForceEEShutdown+0x31
3f 0028ec70 702a9faf     clr!SystemNative::Exit+0x4f

接下来研究下它要进入到什么托管方法中,这个答案就在
UMEntryThunk.m_pManagedTarget
字段里,参考源码如下:


class UMEntryThunk
{
private:
	// The start of the managed code
	const BYTE* m_pManagedTarget;

	// This is used for profiling.
	PTR_MethodDesc m_pMD;
}

有了这些前置知识就可以用 windbg 轻松挖掘。


0:040> kb 5
 # ChildEBP RetAddr      Args to Child              
00 0afdf62c 70e75e0b     c0020001 00000001 00000001 KERNELBASE!RaiseException+0x58
01 0afdf648 70f63bf5     006e0fe0 0afdf67c 70b6f1da clr!COMPlusThrowBoot+0x1a
02 0afdf654 70b6f1da     0698ade8 00580a38 0698ade8 clr!UMThunkStubRareDisableWorker+0x25
03 0afdf67c 77a9571e     00000000 00000001 7d723ac9 clr!UMThunkStubRareDisable+0x9
04 0afdf6bc 77a80f0b     0afdf71c 006e0fe0 006f6c10 ntdll!RtlpTpTimerCallback+0x7a

0:040> dp 00580a38 L2
00580a38  00386580 008f2eb8

0:040> !U 00386580
Unmanaged code
00386580 e9ab390000      jmp     00389f30
...

0:040> !ip2md 00389f30
MethodDesc:   0018af94
Method Name:  xxx._checkInput1(IntPtr, Boolean)
Class:        00435a7c
MethodTable:  0018afd8
mdToken:      06000034
Module:       0018a6a8
IsJitted:     yes
CodeAddr:     00389f30
Transparency: Critical

通过一顿反解果然是一个托管回调函数,分析到这里ztm的开心哈,感觉马上就要看到光了,仔细找了下代码,果然是借助Windows线程池创建了一个定时事件,无语了,截图如下:


到这里就真相大白了,退出进程的时候一定要先调用C#的
Dispose()
方法把非托管的Timer给关掉,否则就会出现这种偶发的崩溃异常。

3. 一些题外话

这个dump的错误码非常有误导性,一个是外部的
c0020001
,一个内部的
8007042Bh
,尤其是搜内部的 8007042Bh 会把你带入到误区里,让你修复系统文件啥的,其实就是一个固定的死值,没有意义的,参见汇编代码。


0:000> ub 70f63bf5
clr!UMThunkStubRareDisableWorker+0x7:
70f63bd7 c9              leave
70f63bd8 e8d47fc3ff      call    clr!CanRunManagedCode (70b9bbb1)
70f63bdd 8b7508          mov     esi,dword ptr [ebp+8]
70f63be0 85c0            test    eax,eax
70f63be2 7511            jne     clr!UMThunkStubRareDisableWorker+0x25 (70f63bf5)
70f63be4 b92b040780      mov     ecx,8007042Bh
70f63be9 c7460800000000  mov     dword ptr [esi+8],0
70f63bf0 e8f721f1ff      call    clr!COMPlusThrowBoot (70e75dec)

所以还是多以代码说话,少道听途说陷入迷途不知返。

三:总结

说实话这个dump分析起来还是挺有难度的,需要你对
Windows线程池

clr源码实现
有一个基础了解,否则很难构造出完整证据链。

图片名称

写在前面

在日常开发中,我们经常会看到各种各样的启动画面。例如以下几种

① spring项目启动画面

springboot启动画面


mybatisplus
启动画面

mybatis启动画面

③若依项目启动画面

若依启动画面

还有很多各式各样好看的启动画面,那么怎么定制这些启动画面呢?

一、小试牛刀

① 新建一个
SpringBoot
项目

新建springboot项目

②在项目的
resources
目录下新建一个
banner.txt
文件,然后将以下佛祖保佑内容粘贴到里面

                   _ooOoo_
                  o8888888o
                  88" . "88
                  (| -_- |)
                  O\  =  /O
               ____/`---'\____
             .'  \\|     |//  `.
            /  \\|||  :  |||//  \
           /  _||||| -:- |||||-  \
           |   | \\\  -  /// |   |
           | \_|  ''\---/''  |   |
           \  .-\__  `-`  ___/-. /
         ___`. .'  /--.--\  `. . __
      ."" '<  `.___\_<|>_/___.'  >'"".
     | | :  `- \`.;`\ _ /`;.`/ - ` : | |
     \  \ `-.   \_ __\ /__ _/   .-` /  /
======`-.____`-.___\_____/___.-`____.-'======
                   `=---='
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
            佛祖保佑       永无BUG

③ 启动项目,看看效果

无需任何其他配置,我们只需要重新启动项目,控制台就可以打印我们定制的启动画面

控制台启动画面

二、在线制作banner

这里提供几个生成banner的网站,上面小节的“佛祖保佑,永无BUG”也是通过下面在线网站生成的


http://patorjk.com/software/taag/

下面截图中以生成
www.xiezhrspace.cn
为例,我们可以选择不同字体

在线生成banner网址1


https://www.bootschool.net/ascii

在线生成banner网址2


http://www.network-science.de/ascii/

在线生成banner网址3


https://www.degraeve.com/img2txt.php

这个网站比较厉害,可以根据在线图片来转换。而且还可以生成彩色的

我们找一张冰冰的图来试试,
https://pic3.zhimg.com/v2-c19edbc9051caddc6b0eb5e6f53ae55a_r.jpg

根据在线图片生成txt

左边是原图,右边是生成的banner.txt

生成后的图


https://www.fontke.com/tool/image2ascii/

这个在线网站也可以根据上传图片生成

在线生成banner网址5

三、自定义Banner颜色

不少小伙伴不喜欢黑白的启动界面,
SpringBoot
提供了
AnsiColor
枚举类来控制
banner.txt
的颜色显示

比如,我们想要将上面的佛祖变成金黄色的,我们只需要在佛祖字符的最前面添加
${AnsiColor.BRIGHT_YELLOW}
代码即可

一尊金色的佛祖就可以出来了

自定义Banner颜色

注:
由于版本原因,小伙伴设置好之后可能颜色不会改变,我们可以在
aplication.properties

application.yml
文件中添加如下配置

#aplication.properties
spring.output.ansi.enabled=always
#application.yml
spring:
  output:
    ansi:
      enabled: always

四、Banner其他设置

除了上面的基本设置之外,我们还可以在
Banner.txt
文件中加入一些属性

  • ${application.version}
    获取
    MANIDEST.MF
    文件中版本号
  • ${application.formatted-version}
    格式化后的
    {application.version}
    版本信息
  • ${spring-boot.version}
    SpringBoot
    的版本号
  • ${spring-boot.formatted-version}
    格式化后的
    {spring-boot.version}
    版本信息

五、关闭Banner

如果小伙伴们不喜欢banner这种信息,想要关闭它。

我们可以修改入口类的
main
方法来实现,具体代码如下

@SpringBootApplication
public class CustomBannerDemoApplication {

    public static void main(String[] args) {
        SpringApplication app = new SpringApplication(CustomBannerDemoApplication.class);
        app.setBannerMode(Banner.Mode.OFF);
        app.run(args);
    }

}

其中
app.setBannerMode(Banner.Mode.OFF)
代表
Banner
模式关闭

当然了,我们也可以在
application.yml
中配置关闭

spring:
  main:
    banner-mode: off

本期内容到这儿就结束了,
★,°
:.☆( ̄▽ ̄)/$:
.°★
。 希望对您有所帮助

我们下期再见 ヾ(•ω•`)o (●'◡'●)

你是否注意到,现在主流的浏览器如 Chrome、Edge、Brave 和 Opera 都采用了谷歌的 Chromium 引擎?同时,谷歌每年不惜花费数十亿美元,确保其搜索引擎在 Safari 中的默认地位,甚至连 Firefox 也难逃商业利益的影响,这使得谷歌在浏览器和搜索引擎市场“一家独大”。

GitHub 创始人兼前 CEO 克里斯·汪斯崔斯 (Chris Wanstrath) 认为世界需要一款有独立精神的开源浏览器,不是要替代谷歌的地位,而是因为
多样性是创新的催化剂
。所以,他决定个人出资 100 万美元,赞助这款独立、非盈利、开源的新浏览器—— Ladybird 浏览器,它的独立性体现在两个方面:

  1. 技术:不使用 Blink、WebKit、Gecko 或任何其他浏览器引擎的代码
  2. 收益:虽然资金来自赞助商,但赞助商无权干涉项目的开发和运营

值得一提的是,这并非克里斯第一次干此类事情。20 年前,他就曾在《纽约时报》为 Firefox 1.0 发布购买了两页广告,以示支持。

说回到上周热门的开源项目,它们分别是高盛开源的量化 Python 工具库、开源的活动和票务管理平台、开源的 2FA 验证器、所有人都可以用的开源语音合成模型,以及 Spring 源码阅读教程。

  • 本文目录
    • 1. 开源新闻
      • 1.1 真正独立的开源浏览器:Ladybird
    • 2. 开源热搜项目
      • 2.1 高盛开源的量化金融 Python 库:gs-quant
      • 2.2 开源的活动和票务管理平台:Hi.Events
      • 2.3 下一代数据科学 IDE:Positron
      • 2.4 开源的 2FA 验证器:Ente
      • 2.5 为所有人准备的开源语音合成模型:fish-speech
    • 3. HelloGitHub 热评
      • 3.1 Spring 源码阅读:spring-reading
      • 3.2 谷歌服务框架的开源替代品:GmsCore
    • 4. 结尾

1. 开源新闻

1.1 真正独立的开源浏览器:Ladybird

主语言:C++

Star:11k

该项目作者想要从头构建一个完全独立的开源 Web 浏览器,所以他从自己写的 SerenityOS 操作系统中分离出浏览器引擎部分,计划基于此做一个全新、跨平台的开源浏览器,它没有来自其它浏览器的代码。目前尚未发布可供下载的安装包,计划在 2026 夏天发布第一个 Alpha 版本。

GitHub 地址→
github.com/LadybirdBrowser/ladybird

2. 开源热搜项目

2.1 高盛开源的量化金融 Python 库:gs-quant

主语言:Python

Star:6.2k

周增长:2.3k

该项目是由高盛开发用于量化交易的 Python 工具包,它是专为量化金融领域设计的 Python 库,已在高盛内部使用多年,支持开发量化交易策略、分析/可视化金融数据和风险管理等功能。此库与高盛的服务高度集成,不登录无法使用高盛提供的市场数据和模型等专业功能。

from gs_quant.analytics.datagrid import DataColumn, DataRow, DataGrid
from gs_quant.analytics.processors import LastProcessor, EntityProcessor
from gs_quant.data.coordinate import DataCoordinate, DataMeasure, DataFrequency
from gs_quant.markets.securities import Asset, AssetIdentifier
from gs_quant.session import GsSession

GsSession.use()

GS = Asset.get("GS UN", AssetIdentifier.BLOOMBERG_ID)
AAPL = Asset.get("AAPL UW", AssetIdentifier.BLOOMBERG_ID)
AMZN = Asset.get("AMZN UW", AssetIdentifier.BLOOMBERG_ID)

rows = [DataRow(GS), DataRow(AAPL), DataRow(AMZN)]

trade_price = DataCoordinate(measure=DataMeasure.TRADE_PRICE, frequency=DataFrequency.REAL_TIME)

col_0 = DataColumn(name="Name", processor=EntityProcessor(field="short_name"))
col_1 = DataColumn(name="Last", processor=LastProcessor(trade_price))

columns = [col_0, col_1]

datagrid = DataGrid('My First DataGrid!', rows=rows, columns=columns)

datagrid.initialize()
datagrid.poll()
print(datagrid.to_frame())

GitHub 地址→
github.com/goldmansachs/gs-quant

2.2 开源的活动和票务管理平台:Hi.Events

主语言:PHP

Star:450

周增长:400

该项目是采用 PHP 开发的票务平台,提供了从活动创建到票务销售的全套解决方案,它支持数据分析、多种门票类型、活动页、签到工具、优惠码等功能,能够帮助组织者轻松管理活动和销售各种规模活动的门票。

GitHub 地址→
github.com/HiEventsDev/Hi.Events

2.3 下一代数据科学 IDE:Positron

主语言:TypeScript

Star:1.5k

周增长:1k

这是一个为数据分析设计的集成开发环境,它基于 VSCode 构建了一个可复制的编写和发布的桌面开发环境,支持运行 Python 和 R 代码、自动补全等功能,适用于数据科学家和分析师进行数据处理和分析。

GitHub 地址→
github.com/posit-dev/positron

2.4 开源的 2FA 验证器:Ente

主语言:Flutter

Star:11k

周增长:800

该项目是提供端到端加密的服务,内含基于此服务(Ente)的两款产品,它们分别是云相册(免费试用)和 2FA 验证器(永久免费)。永久免费的 Ente Auth,它可帮助你在移动设备上生成并存储两步验证 (2FA) 令牌。

GitHub 地址→
github.com/ente-io/ente

2.5 为所有人准备的开源语音合成模型:fish-speech

主语言:Python

Star:4.6k

周增长:2k

该项目是由 Fish Audio 开发的基于 VQGAN+Llama 的文本转语音模型,它仅需 4GB 显存即可在个人设备上轻松运行和微调(16GB),支持中英日语和音色调整,语音合成效果出色。

GitHub 地址→
github.com/fishaudio/fish-speech

3. HelloGitHub 热评

在这个章节,将会分享下本周 HelloGitHub 网站上的热门开源项目,欢迎与我们分享你上手这些开源项目后的使用体验。

3.1 Spring 源码阅读:spring-reading

主语言:Java

这是一份讲解 Spring 源码的图文教程,内容涵盖了 Spring 框架的核心概念和关键功能,而且还贴心地标注了难度等级,更加便于学习。

项目详情→
hellogithub.com/repository/f43b683fa175499ca3af4e9b1684e88b

3.2 谷歌服务框架的开源替代品:GmsCore

主语言:Java

该项目是一个开源的替代 Google Play 服务的解决方案,它可以让无法安装或不想用 Google 服务的用户,运行依赖谷歌服务的 Android 应用。

项目详情→
hellogithub.com/repository/91571ba628534eff867d556bfec45885

4. 结尾

以上就是本期「GitHub 热点速览」的全部内容,希望你能够在这里找到自己感兴趣的开源项目,如果你有其他好玩、有趣的 GitHub 开源项目想要分享,欢迎来
HelloGitHub
与我们交流和讨论。

往期回顾