背景:
经常在做aosp开发时候经常面临一个问题,那就是从google或者清华源repo了aosp代码后,肯定会进行一些aosp代码的修改,但是因为大部分国内开发者都无法把这些修改commit进行push到google后台。所以导致自己的相关修改无法被有效的保存到服务器,一直commit在自己的本地,这样只是commit本地方式还是非常非常不方便,一旦更换电脑,或者说代码重新repo都无法很方便把自己前面commit进行合入。
针对上面提到的痛点,那么有什么办法能够帮助解决么?下面介绍2种常见方案来解决该痛点。
方案1
核心原理:
把从清华源repo下来的aosp代码的所有git仓库,把他们统一迁移到自己的git服务器后台比如gitea等。这样在自己git服务器后台就拥有整套的aosp代码仓库,然后在出现repo自己服务器的aosp源码, 后续修改自己服务器repo的源码就可以很方便的进行push到服务器进行保存。
缺点:
这个相当于要把整套aosp的代码仓库都进行保存到自己git服务器后台,整个过程耗费时间,最重要是保存整套aosp代码的git仓库需要大量的硬盘空间,这个很多同学都是本地电脑搭建的git服务器后台,所以这个还是一个比较大的痛点。
针对上面这个方案占用空间大的痛点问题,那么是否有其他方案,可以实现不需要保存整套代码git库,只需要保存自己的修改,aosp代码依旧可以从清华源等地方下载,自己的所有修改commit只是push保存到git服务器后台。
方案2
核心原理:
aosp代码本身可以从google服务器,清华源等地方进行repo,不需要额外保存自己服务器,只需要保存自己针对aosp修改的commit到服务器后台既可以。这样既可以实现节省空间目的,也可以实现对aosp的所有修改进行了相关的保存目的。
那么具体方案2如何实现呢?这里我们设计的是使用一个shell脚本就可以,我们可以借助AI来帮忙实现一下这个shell脚本。
Shell脚本的实现
实现的shell脚本代码如下:
#!/bin/bash
# 修复版 AOSP Patch 生成脚本
# 修复问题:
# 1. 现在能正确遍历所有仓库(包括framework/native等)
# 2. 确保patch文件生成到正确的aosp_patches目录下
# 设置输出目录(使用绝对路径避免位置问题)
PATCH_BASE_DIR="$(realpath "${1:-aosp_patches}")"
mkdir -p "$PATCH_BASE_DIR"
# 初始化计数器和清单文件
total_repos=0
total_patches=0
MANIFEST_FILE="$PATCH_BASE_DIR/patch_manifest.csv"
echo "repo_path,commit_hash,commit_subject,patch_file" > "$MANIFEST_FILE"
echo "开始扫描所有AOSP仓库中的未push提交..."
# 修复1:使用正确的repo遍历命令
repo list | while read -r repo_line; do
# 提取仓库路径
repo_path=$(echo "$repo_line" | awk '{print $1}')
# 进入仓库目录
if [ ! -d "$repo_path" ]; then
echo "警告: 仓库目录不存在: $repo_path"
continue
fi
pushd "$repo_path" > /dev/null || continue
# 检查是否有未push的commit
unpushed_count=$(git log --branches --not --remotes --oneline 2>/dev/null | wc -l)
if [ "$unpushed_count" -gt 0 ]; then
# 修复2:确保创建正确的目标目录结构
repo_patch_dir="$PATCH_BASE_DIR/$repo_path"
mkdir -p "$repo_patch_dir"
# 获取未push的commit列表
commits=$(git log --branches --not --remotes --pretty=format:"%h" --no-color)
# 为每个commit生成patch
commit_count=0
for commit in $commits; do
# 获取commit信息并处理特殊字符
commit_subject=$(git log -1 --pretty=format:"%s" "$commit" |
tr -d "\n" |
tr "/" "_" |
tr " " "_" |
sed 's/[^a-zA-Z0-9_]/./g' |
cut -c -50)
# 生成带描述的文件名
patch_filename="${commit}_${commit_subject}.patch"
patch_file="$repo_patch_dir/$patch_filename"
# 生成标准patch文件
git format-patch -1 --no-stat --no-numbered --stdout "$commit" > "$patch_file"
# 添加元信息头
sed -i "1i # Repository: $repo_path\n# Commit Hash: $commit\n# Original Subject: $(git log -1 --pretty=format:%s $commit)\n#" "$patch_file"
# 记录到清单文件(使用绝对路径)
echo "\"$repo_path\",\"$commit\",\"$commit_subject\",\"$(realpath --relative-to="$PATCH_BASE_DIR" "$patch_file")\"" >> "$MANIFEST_FILE"
commit_count=$((commit_count + 1))
echo "生成patch: $(realpath --relative-to="$PATCH_BASE_DIR" "$patch_file")"
done
echo "[✓] $repo_path: 生成 $commit_count 个patch"
total_patches=$((total_patches + commit_count))
total_repos=$((total_repos + 1))
popd > /dev/null || exit 1
else
popd > /dev/null
fi
done
echo "=============================================="
echo "扫描完成!"
echo "共在 $total_repos 个仓库中发现 $total_patches 个未push的commit"
echo "Patch文件已保存到: $PATCH_BASE_DIR"
echo "目录结构:"
tree -L 3 "$PATCH_BASE_DIR" | head -15
echo "=============================================="
# 生成修复版应用脚本
APPLY_SCRIPT="$PATCH_BASE_DIR/apply_patches.sh"
cat > "$APPLY_SCRIPT" << 'EOF'
#!/bin/bash
# AOSP Patch 应用脚本(修复版)
# 确保正确解析相对路径
PATCH_BASE_DIR="$(cd "$(dirname "$0")" && pwd)"
MANIFEST="$PATCH_BASE_DIR/patch_manifest.csv"
SUCCESS_LOG="$PATCH_BASE_DIR/success.log"
FAIL_LOG="$PATCH_BASE_DIR/fail.log"
# 初始化日志
echo "Patch应用报告 - $(date)" > "$SUCCESS_LOG"
echo "失败记录 - $(date)" > "$FAIL_LOG"
success_count=0
fail_count=0
# 读取CSV格式的清单文件
tail -n +2 "$MANIFEST" | while IFS=, read -r repo_path commit_hash commit_subject patch_file; do
# 清理CSV字段中的引号
repo_path=${repo_path//\"/}
patch_file=${patch_file//\"/}
# 获取完整patch路径
full_patch_path="$PATCH_BASE_DIR/$patch_file"
echo -n "正在应用 $commit_hash ($commit_subject) 到 $repo_path ... "
# 进入仓库目录
if pushd "$repo_path" >/dev/null 2>&1; then
# 应用patch
if git am --whitespace=nowarn "$full_patch_path" >/dev/null 2>&1; then
echo "成功" | tee -a "$SUCCESS_LOG"
success_count=$((success_count + 1))
else
echo "失败" | tee -a "$FAIL_LOG"
git am --abort >/dev/null 2>&1
fail_count=$((fail_count + 1))
fi
popd >/dev/null
else
echo "仓库不存在: $repo_path" | tee -a "$FAIL_LOG"
fail_count=$((fail_count + 1))
fi
done
echo "=============================================="
echo "应用结果统计:"
echo "成功: $success_count"
echo "失败: $fail_count"
echo "----------------------------------------------"
echo "成功记录: $SUCCESS_LOG"
echo "失败记录: $FAIL_LOG"
echo "=============================================="
if [ "$fail_count" -gt 0 ]; then
echo "警告: 有 $fail_count 个patch应用失败!"
exit 1
fi
EOF
chmod +x "$APPLY_SCRIPT"
echo "已生成修复版应用脚本: $APPLY_SCRIPT"
上面代码保存到generate_patches.sh文件,generate_patches.sh放到aosp的根目录。
使用示例:
生成patch:
./generate_patches.sh /path/to/save_patches
生成的patch文件结构:
/path/to/save_patches/
├── frameworks/
│ └── base/
│ ├── abcd123_Fix_memory_leak.patch
│ └── efgh456_Add_new_feature.patch
├── patch_manifest.csv
└── apply_patches.sh
应用patch:
/path/to/save_patches/apply_patches.sh
这个改进版本能更清晰地标识每个patch的用途,同时在应用时能提供更详细的信息,方便问题排查。
实战结果
下面是我在aosp14上的一个实战体验:
test@test:~/disk2/aosp14$ rm aosp_patches/ -rf;./generate_asop_patches.sh
开始扫描所有AOSP仓库中的未push提交...
生成patch: frameworks/base/768227252484_modify_recent_show_mutilwindow_split_task_thumbnai.patch
生成patch: frameworks/base/c0b465576254_add_for_left.right.bar.patch
生成patch: frameworks/base/2408081e2df7_Revert_.modify_dumpsys_activity_containers_show_st.patch
生成patch: frameworks/base/60a6bd792ddd_modify_dumpsys_activity_containers_show_style.patch
生成patch: frameworks/base/2e980f7dadfc_add_ratio_for_cmd_start_splitscreen.patch
生成patch: frameworks/base/244c2ac15f46_start_splitscreen_by_use_intent_not_taskId.patch
生成patch: frameworks/base/be2cf046814e_add_a_cmd_startTask_for_splitscreen.patch
[✓] frameworks/base: 生成 7 个patch
==============================================
扫描完成!
共在 0 个仓库中发现 0 个未push的commit
Patch文件已保存到: /home/test/disk2/aosp14/aosp_patches
目录结构:
/home/test/disk2/aosp14/aosp_patches
├── frameworks
│ └── base
│ ├── 2408081e2df7_Revert_.modify_dumpsys_activity_containers_show_st.patch
│ ├── 244c2ac15f46_start_splitscreen_by_use_intent_not_taskId.patch
│ ├── 2e980f7dadfc_add_ratio_for_cmd_start_splitscreen.patch
│ ├── 60a6bd792ddd_modify_dumpsys_activity_containers_show_style.patch
│ ├── 768227252484_modify_recent_show_mutilwindow_split_task_thumbnai.patch
│ ├── be2cf046814e_add_a_cmd_startTask_for_splitscreen.patch
│ └── c0b465576254_add_for_left.right.bar.patch
└── patch_manifest.csv
2 directories, 8 files
==============================================
已生成修复版应用脚本: /home/test/disk2/aosp14/aosp_patches/apply_patches.sh
上面可以看出已经针对framework/base目录识别到了有7个本地commit,看看对应的生成patch目录情况:
test@test:~/disk2/aosp14$ tree aosp_patches/
aosp_patches/
├── apply_patches.sh
├── frameworks
│ └── base
│ ├── 2408081e2df7_Revert_.modify_dumpsys_activity_containers_show_st.patch
│ ├── 244c2ac15f46_start_splitscreen_by_use_intent_not_taskId.patch
│ ├── 2e980f7dadfc_add_ratio_for_cmd_start_splitscreen.patch
│ ├── 60a6bd792ddd_modify_dumpsys_activity_containers_show_style.patch
│ ├── 768227252484_modify_recent_show_mutilwindow_split_task_thumbnai.patch
│ ├── be2cf046814e_add_a_cmd_startTask_for_splitscreen.patch
│ └── c0b465576254_add_for_left.right.bar.patch
└── patch_manifest.csv
2 directories, 9 files
可以看到确实有针对一个个commit生成patch,后期到了新的aosp代码,只需要拷贝这个目录到根目录然后进行apply_patches.sh既可以。
但是也发现有bug,主要是针对这些未提交commit仓库并没有识别全面,比如framework/native等目录是没有识别正确,让AI进行修改其实一直也无法修改正确,这块其实还是AI生成的代码并没有去分析我们实际framework/native的情况,或者这种情况AI其实也没有很好的方法规则来识别过滤出没有push的commit,所以还是需要程序员们看懂修改去修改修复。
使用AI帮助编写一些提效的脚本工具一些感悟:
上面的AI生成的脚本确实整体上帮我们完成了%70左右工作,但其实还是会有一些bug,比如识别没有push的commit其实需要考虑的实际的aosp仓库状态情况,所以实际使用起来才会发现有相关的bug。但是大家注意一旦有了bug后,发现只是把bug告诉AI去修改,发现AI基本上很难修改好,毕竟AI其实还是属于大模型生成的,目前没有实际分析你场景具体问题原因,帮你准确修改好相关bug,所以这块大家也不要期待AI完全可以写出一个适合你实战的代码。
虽然AI无法完美满足你的实战需求代码,但是AI确实可以给你生成一个基本上可以用的成品代码,这个已经最少帮你节省了%70以上时间了,万事开头难,AI都帮助你开好了头,也帮你实现了一个基本可用的代码,你只需要在这个基础上改善完善他的功能,修复一些bug既可以,所以AI完全替代程序员这个事情是不太存在的,但是AI可以大大提升我们每个程序员的开发效率,让AI做出一些基本可用的模块类工作,节省我们大量的时间成本,我们程序员注意力集中在更高难度的一些AI无法实现需求和bug上。
总结AI对于我们程序员影响:
不用过多的去焦虑AI是否会完全取代我们程序员,因为很多现实场景需求还是很复杂的,完全取代程序员不太可能,但是AI确实不在编程方面帮助我们提升很大的效率,我们可以多使用AI来帮助做一些模块类的工作,自己经历投入到更加复杂,有门槛,有技术含量,AI无法完成的一些工作。
同时AI生成的那些代码,大家也要进行熟悉,不能过渡依赖AI,因为产生bug,或者需求变更的,都需要程序员自己去开发解决,过渡依赖可能浪费大量时间去提问,却得不到好的结果。
更多framework实战干货,请关注下面的“千里马学框架”。