Android 7.1 车机 Android 系统 在线升级,将安装到下载到/data/目录下面

最近按项目要求,需要做一个车机Android在线升级操作,但是cache内存太小了,最后只能寄存希望在 data/文件夹下,但是data/目录在6.0之后禁止recovery读取data文件.最后的解决方案是在/data/文件下创建一个系统app能够操作的文件夹,进行升级操作.
1、升级流程
Android自带升级流程 API RecoverySystem.java (framework/base/core/java/android/os/RecoverySystem.java)
调用如下代码就可以进行升级操作,对你没看错,就是一句代码,将你下载好的压缩包路径传过去就行.

   private void excuteUpdateZip(String local_path) {
        // TODO Auto-generated method stub
        try {
            RecoverySystem.installPackage(this, new File(local_path));
            //RecoverySystem.installPackage(this, new File(local_path));
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

但是 事情永远是比想象的麻烦, 因为我们的车机要求的是将压缩包放到 /data/目录下. 那放就放吧 先编译好一个全包 使用命令

adb root 
adb remount
adb push  updata.zip /data/

使用模拟升级命令进行升级操作

adb shell "echo --update_package=/data/update.zip > /cache/recovery/command"
 
adb shell sync
 
adb reboot recovery

就这样成功进行了升级,what?完成了? 这么简单,原来这才是跳坑的开始,看到生面测试成功了之后,迫不及待的在自己的程序中将路径填写成 /data/update.zip ,开始了升级操作,结果失败了.开始检查原因
是不是AndroidManifest.xml中没有添加 如下权限
android:sharedUserId=“android.uid.system”
查看添加了,是不是没有对自己的apk进行系统签名?发现也签名了(如何给APK系统签名),没有放到system/app/文件夹下?也放了,.那原因出在哪里那?不想了,先去看看log

Android机器中 /cache/recovery/的目录结构如下:

cache/        
└── recovery      
    ├── last_install
    ├── last_kmsg  #系统升级的时候的全log. 如果有last_kmsg.1 
                   #那last_kmsg 永远是最后一次升级的log,所以每
                   #次只查看last_kmsg就行
    ├── last_locale
    └── last_log   #升级过程中的简log,能看到为何升级失败
 

在log中查看到的是 --update_package=@/cache/recovery/block.map 看到这个结果的时候,第一感觉就是apk没有安装成功,于是加了log 发现加的log 成功打印,吓了一跳,自己撞见鬼了?

抱着程序员不明原因不放弃的心态,看了一下RecoverySystem.java 中的 installPackage 方法,原来是 installpackage在代码中做了限制, 要是设置的路径是以 /data/ 开头强制更改@/cache/recovery/block.map

  @SystemApi
    public static void installPackage(Context context, File packageFile, boolean processed)
            throws IOException {
        //省略代码......
       if (filename.startsWith("/data/")) {
                if (processed) {
                   //省略代码......
                } else {
                //省略代码......
                }
                //TODO 重点就是这句话,将路径强制求改
                filename = "@/cache/recovery/block.map";
            } 
            final String filenameArg = "--update_package=" + filename + "\n";
            final String localeArg = "--locale=" + Locale.getDefault().toString() + "\n";
            final String securityArg = "--security\n";
            String command = filenameArg + localeArg;
            //省略代码......
        }
    }

看到这,挡了我的路,必定铲除,将代码很愉快的注掉了,重新编译进行测试.
激动的等待中…
又失败了?难道还有拦路虎? 我的心要崩溃了,为什么还是失败,还是查看log发现 --update_package=data/update.zip . 这么看来已经能写到重启文件中了.

查看log提示是 --update_package=data/update.zip Permission Denied 看来是datarecover没有权限读取/data目录啊
快速验证 是不是selinux问题 可以修改 BoardConfig.mk 添加如下代码 编译boot文件测试,如下代码是禁用selinux代码
BOARD_KERNEL_CMDLINE += androidboot.selinux=permissive
2.selinux权限问题
经过一番调查 发现 data的 type属于 system_data_file类型的
在file_contexts中可以查看到
/data(/.*)? u:object_r:system_data_file:s0
在recovery.te中发现了如下代码

neverallow recovery data_file_type:file { no_w_file_perms no_x_file_perms };
neverallow recovery data_file_type:dir no_w_dir_perms;

也就是说明 recover.te何时都不能读取和操作/data/目录,那怎么办?当然是有办法的,我们可以新建一个文件夹 和自定义文件类型啊
首先是开机的时候要有一个文件夹
我们可以在init.rc 或者 init.qcom.rc中创建一个文件夹

#Create directory for download
mkdir /data/download 0771
chown system system /data/download

这样的话 我们已经创建了 文件夹,并且system app级别的应用可以读取.

那既然存储好了之后是不是下面需要 recovery可以读取到文件那?系统不允许读取 recovery.te /data/路径.那我们就自己创建一个文件类型,在file_contexts 增加类型

/data/download(/.*)?           u:object_r:download_data_file:s0  

然后在file.te中定义download_data_file类型, 注意是只属于file_type类型的。
type download_data_file, file_type;
然后在recovery.te中增加对download_data_file的权限

allow recovery download_data_file:dir { write search remove_name };
allow recovery download_data_file:file { read getattr open unlink };

因为data目录有可能需要进行加密处理,我们还需要在uncrypt.te中增加如下。

allow uncrypt download_data_file:dir { search getattr };  
allow uncrypt download_data_file:file { getattr read open };

以上就是完成了添加,我本地全编译,测试成功.
最后升级的过程中可能会看到Permission Denied 最后可以cat last_kmsg 查看 最后一样都会输出失败的权限原因
比如 :

avc:  denied  { open } for  pid=381 comm="recovery"
path="/data/download/update.zip" dev="mmcblk0p51" ino=513074 
scontext=u:r:recovery:s0 tcontext=u:object_r:download_data_file:s0 
tclass=file permissive=0

这种权限只能报错什么权限添加什么权限,我们可以遵循这个方法,从头开始寻找关键对象,然后调整一下顺序,生成一条语句,最后将该语句填写到.te中即可。
denied { open } scontext=u:r:recovery:s0 tcontext=u:object_r:download_data_file:s0 tclass=file

         A                                    B                                                             C                                                  D

         B                                    C                                                             D                                                   A

allow recovery download_data_file:tclass open;
如果升级没有错误,APP操作文件夹中的文件无效时,可以在操作的时候执行如下命令,如果报了相关权限问题,加上即可,
adb shell dmesg | grep denied

其它版本的系统升级,升级包存储在/data/分区的情况可以参考这篇文章,大同小异的。

<think>好的,用户遇到了Git合并时本地更改会被覆盖的问题,需要解决方案。根据之前的引用资料,解决方法主要有commit、stash和revert三种。首先,我得确认用户的具体情况,比如他们的本地更改是否已经完成,是否需要保留,或者是否可以丢弃。用户可能不太清楚这三种方法的适用场景,需要详细解释每个选项的步骤和优缺点。比如,commit适用于需要保留更改的情况,stash适合临时保存以便后续恢复,而revert则是直接撤销更改,适用于不需要保留的情况。需要结构清晰,分点说明,每个方法都给出操作步骤和适用场景,帮助用户理解哪种情况最适合他们。还要注意使用中文,避免技术术语过于复杂,让用户容易理解。同时,生成相关问题,可能涉及如何恢复stash的内容,或者如何避免频繁冲突等,扩展用户的知识点。另外,要确保LaTeX格式正确,但在这个问题中可能用不上数学公式,所以主要关注代码块和引用标识。检查引用是否正确,比如引用[^1]和[^2]的来源是否相关,用户提供的引用内容是否准确对应解决方案。 最后,确保回答真实可靠,操作步骤准确无误,避免误导用户。可能还需要提醒用户根据具体情况选择方法,比如如果有未完成的实验性代码,stash可能是更好的选择,而如果是确定要保留的修改,则应该commit。</think>要解决Git合并时本地更改被覆盖的问题,可根据不同场景选择以下三种方法: ### 一、提交本地更改(commit) **适用场景**:当本地更改已测试通过且需要保留到版本历史中。 **操作步骤**: 1. 将改动添加到暂存区: ```bash git add . # 添加所有文件 # 或指定文件 git add file1.txt file2.py ``` 2. 提交更改并添加描述: ```bash git commit -m "完成用户登录模块优化" ``` 3. 执行合并操作: ```bash git merge origin/main ``` **优点**:保留完整的开发记录,便于后续追溯[^1]。 ### 二、暂存更改(stash) **适用场景**:需要临时保存未完成的修改(如调试代码),优先处理合并操作。 **操作步骤**: 1. 保存当前工作状态: ```bash git stash # 可选添加备注 git stash save "用户登录模块调试代码" ``` 2. 查看暂存记录列表: ```bash git stash list ``` 3. 合并远程分支: ```bash git merge origin/main ``` 4. 恢复暂存内容: ```bash git stash pop # 恢复并删除最近一次暂存 # 或指定特定暂存 git stash apply stash@{1} ``` **优点**:保持工作目录整洁,特别适合处理紧急合并任务[^2]。 ### 三、撤销本地更改(revert) **适用场景**:本地修改可丢弃(如实验性代码或错误修改)。 **操作步骤**: 1. 撤销所有未提交的修改: ```bash git checkout -- . # 全部文件 # 或指定文件 git checkout -- file1.txt ``` 2. 执行合并操作: ```bash git merge origin/main ``` **风险提示**:此操作不可逆,需确认文件无需保留。 --- ### 对比决策表 | 方法 | 保留记录 | 可恢复性 | 适用阶段 | |---------|----------|----------|------------------| | commit | ✅ | ✅ | 功能开发完成时 | | stash | ❌ | ✅ | 开发中途临时切换 | | revert | ❌ | ❌ | 放弃无效修改 | ### 扩展应用场景 - 当存在多个暂存时,可用`git stash list`查看记录,通过`git stash apply stash@{n}`精准恢复 - 合并后出现冲突时,可使用`git mergetool`可视化工具解决冲突 - 长期分支开发推荐使用`git rebase`保持提交历史线性
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值