Android 系统应用重名install安装失败分析解决

news2025/3/2 2:12:57

Android 系统应用重名install安装失败分析解决

文章目录

  • Android 系统应用重名install安装失败分析解决
    • 一、前言
      • 1、Android Persistent apps 简单介绍
    • 二、系统 persistent 应用直接安装需求分析解决
      • 1、系统应用安装报错返回的信息
      • 2、分析解决
    • 三、其他
      • 1、persistent系统应用install安装调试小结
      • 2、安装persistent系统应用报错在系统源码中简要分析
        • (1)logcat 过滤查看安装apk相关日志:
        • (2)安装失败报错的具体代码位置
      • 3、Android Studio 直接安装persistent系统应用报错分析处理
        • (1) Android Studio 中弹框显示的错误
      • (2)app\build.gradle 适配
        • (3)修改 applicationId
        • (4)dumpsys package 验证安装的apk
      • 4、Android14 Bluetooth系统蓝牙应用调试
        • (1)查看蓝牙应用的安装目录
        • (2)apex目录apk 无法直接替换!
        • (4)蓝牙应用可以直接install 安装成功
        • (5)dumpsys 查看蓝牙应用安装替换情况
      • 5、系统应用设置 persistent="true" 的作用
      • 5、判断应用是否是persistent类型的系统应用
        • (1)AndroidManifest.xml 代码判断签名和属性
        • (2)应用apk文件反编译分析
        • (3)运行环境dumpsys package分析
      • 6、普通应用设置 persistent="true" 有用吗?

一、前言

系统开发过程中,你会发现一些系统应用编译后无法直接安装成功,为啥?
具体是为啥导致无法正常安装?如果要正常安装需要怎么处理?

刚开始我以为是系统应用重名不能直接安装,但是发现有些系统应用是可以直接安装的;
所以还是要研究看看。

本文简单分析解决一下这个问题!

后面复现关键就是 Android 的 persistent 属性,
persistent(翻译:持久的) 属性是系统应用用来保活的应用和服务的。

声明了 android:persistent="true"的系统应用就表示该应用是持久的,无法进行安装。

这种持久系统应用情况,除了替换apk重启或者编译系统大包,如何才能直接替换安装apk调试呢?

下面进行分析一下。这个对系统应用的调试有一定的帮助作用。

1、Android Persistent apps 简单介绍

Persistent apps(持久化应用)是指那些被标记为具有android:persistent="true"属性的应用;
这个属性是定义的AndroidManifest.xml 的 application 标签中;
这种应用一般是系统应用,该进程在系统运行过程中会被特殊对待,kill掉后马上会被系统拉起;

目前系统一些Persistent apps 应用:

系统核心服务应用:SystemUI,输入法框架
关键通信和同步应用:电话应用,短信应用,同步服务应用
还有一些自定义的关键应用

简单的定义 persistent 属性的代码:

    <application
        android:name=".base.MyApplication"
   ...
        android:persistent="true" //持久化
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/SettingsDialog"
        tools:replace="android:appComponentFactory">

如果未定义persistent属性,就是默认的false。普通应用都是未定义这个属性的。

如果普通应用定义这个属性为true,会发生什么呢?最后结论有揭晓。

二、系统 persistent 应用直接安装需求分析解决

并不是Android的所有系统应用都是无法install 安装,
有部分应用是可以直接install安装的,
无法直接install安装的应用,除了 persistent 这种情况,
可能还有其他情况,比如版本兼容,版本号定义等情况,下面只是针对persistent这种情况进行分析处理。

1、系统应用安装报错返回的信息

C:\Users\As11040>adb install E:\Android14\311D2\apk\DebugSystemUI\DebugSystemUI.apk
Performing Streamed Install
adb: failed to install E:\Android14\311D2\apk\DebugSystemUI\DebugSystemUI.apk: 
Failure [INSTALL_FAILED_INVALID_APK: Package com.debug.SystemUI is a persistent app. Persistent apps are not updateable.]

C:\Users\As11040>

这里可以看到报错提示是:Persistent apps 无法更新。

那咋搞?下面就提供一些调试persistent应用的思路。

2、分析解决

下面给出三种解决方案:

第一种方法(每次重启):
    系统remount后,替换DebugSystemUI后,重启就会自动安装替换;
第二种方法(不用重启):
    Android Studio 修改DebugSystemUI的包名,编译这个 应用,修改包名后,就可以安装调试;
第三种方法(重启一次):
    去除系统应用代码的persistent属性,重新编译,按照第一种方法替换apk后,
    后面不用修改应用的包名,就可以直接安装替换apk调试。

上面看起来好像没有一种是非常简单的。实际开发中,调试系统应用可能还会更麻烦。

下面对比一下几种调试手段:

第一种调试方法:
    比较保守,大部分系统开发的都是这样处理的;
    这种调试方法适用于次数较少,简单代码修改的调试;
    每次都要重启比较麻烦耗时。

第二种调试方法:
    Android Studio 中重命名应用包名 applicationId "com.debug.settings2",
    不用修改其他包名相关的地方,就可以直接安装了;
    这种调试方法适用于次数较多或者复杂的代码修改的调试;
    但是这种方法不一定适用于所有应用,自定义开发的应用比较好适配,可以直接用Studio编译;
    有些系统应用不一定能导入到Android Studio中进行编译,或者要适配过程是非常麻烦的;
    系统应用还有导入系统签名,系统framework包和其他相关包;
    如果是非常麻烦的情况就没必要搞了,有些情况不一定能搞得定。

第三种调试方法:
    这种方法比较中和;
    如果既要多次修改,又无法使用Android Studio 进行编译代码的情况;
    第三种调试方法没有用到Android Studio,源码编译就行。

具体情况,使用具体方式就行调试吧。怎么方便怎么搞就行。

上面其实就是说了一下persistent系统应用无法直接安装,
具体要怎么调试就看当时的调试条件了。

三、其他

1、persistent系统应用install安装调试小结

系统代码中限制了persistent的系统应用无法进行直接安装调试;
大概是因为persistent是一直运行的,无法stop或者kill;
如果要调试安装persistent系统应用,大概有三种方法:

(1)替换系统应用apk,重启
(2)把apk源码弄到Android Studio中,修改包名后,直接安装
(3)去系统应用的persistent属性,替换重启后,后面安装调试就不用每次重启了

第二种方法看起来比较简单,虽然不用remount设备,但是有些大型应用适配是非常麻烦的;
第一种和第三种方法都是要解锁设备,remount后才能执行的;
第三种方法是比较简单方便多次调试的。

2、安装persistent系统应用报错在系统源码中简要分析

上面是解决了调试问题,但是不妨分析一下系统源代码,加深一下印象。

(1)logcat 过滤查看安装apk相关日志:
//这里过来安装或者应用管理相关日志信息
console:/ # logcat | grep -i -E "install|PackageManager"

12-10 18:25:08.591 32730 32730 I abb     : StartCommandInProcess(7061636b61676500696e7374616c6c00 package.install. [truncated])
12-10 18:25:08.794   891   955 E PackageManager: No required verifiers
12-10 18:25:08.815   891   955 I PackageManager: Integrity check passed for file:///data/app/vmdl1963375571.tmp
//源码代码中报错的信息:
12-10 18:25:08.828   891   955 W PackageManager: Package com.skg.SystemUI is a persistent app. Persistent apps are not updateable.
//返回到cmd窗口中打印的信息:
12-10 18:25:08.831   891   955 D PackageInstallerSession: Marking session 1963375571 as failed: 
INSTALL_FAILED_INVALID_APK: Package com.skg.SystemUI is a persistent app. Persistent apps are not updateable.

从上面大致可以看到报错的信息,
然后就可以从源码中看看具体发生错误的具体代码位置。

查找过程就不展开说明了,可以源码中grep找到关键字筛选可能的位置。

(2)安装失败报错的具体代码位置

Android14 源码:

framework/base/services/core/java/com/android/server/pm/InstallPackageHelper.java


final class InstallPackageHelper {
    private final PackageManagerService mPm;
    
    ...
    
    @GuardedBy("mPm.mInstallLock")
    private void preparePackageLI(InstallRequest request) throws PrepareFailure {
        final int installFlags = request.getInstallFlags();
        final boolean onExternal = request.getVolumeUuid() != null;
        ...

                  // Prevent persistent apps from being updated
                    if (oldPackage.isPersistent()
                            && ((installFlags & PackageManager.INSTALL_STAGED) == 0)) {
                        throw new PrepareFailure(PackageManager.INSTALL_FAILED_INVALID_APK,
                                "Package " + oldPackage.getPackageName() + " is a persistent app. "
                                        + "Persistent apps are not updateable.");
                    }
    ...

从上面Java代码确实看到了logcat中的报错信息。
上面逻辑看到是安装应用的时候判断了isPersistent()和 installFlags 后就抛出这个异常错误。

isPersistent() 方法很容易理解就是是否定义了 persistent属性的应用;
installFlags 属性应该是一些列属性相关的值,比如是否系统应用,系统签名都是相关的,
这里不继续进行分析,有兴趣的可以看看。

3、Android Studio 直接安装persistent系统应用报错分析处理

这个相当于接上面第二种调试方法展开说明一下。

(1) Android Studio 中弹框显示的错误
Error running 'app' The application could not be installed:
INSTALL_FAILED_INVALID_APK The APKs are invalid. List of apks: [0]
'E:\Studio\project\Android14_311D2\DebugSettings\app\build\intermediates\apk\debug\app-debug.apk

从上面查看并未发现为啥报错,只显示了apk不可用!
哈哈,这种情况咋分析?

其实还得看logcat日志,同样的过滤install|PackageManager是可以看到persistent应用无法替换的错误提示。

这里介绍一下,修改Android Studio 系统应用包名的处理。

(2)app\build.gradle 适配

原本的包名定义:

android {
    namespace 'com.debug.settings'
    compileSdk 34

    defaultConfig {
        applicationId "com.debug.settings"
        minSdk 30
        targetSdk 34
        versionCode 1
        versionName "1.0"

    }

    //系统签名、证书信息在这里配置
   
}

...

上面可以看到有个namespace 和 applicationId 都是定义的应用包名。
其中 namespace 是跟系统资源绑定的,不能随便改,
如果要修改namespace,Java代码里面的定义都要修改,否则会报错;

applicationId 是一个封装的包名,可以随便修改!

(3)修改 applicationId

如果要重新安装这个系统应用的封装包名,修改applicationId 的包名就行:

applicationId "com.debug.settings2"

安装调试发现,会重新生成另外一个 com.debug.settings2 包名的应用,之前的应用是不影响。

(4)dumpsys package 验证安装的apk

同时dumpsys package 查看也是验证查看这个新的包名:


IWB:/ $ dumpsys package com.debug.settings | grep path
    path: /system/priv-app/DebugSettings/DebugSettings.apk
IWB:/ $
IWB:/ $ dumpsys package com.debug.settings2 | grep path
    path: /data/app/~~w3MWD86p2cPawWc2MJun7A==/com.debug.settings2-S3W73_reyyTmvIiB-Vaggg==/base.apk

IWB:/ $ dumpsys package com.debug.settings2 | grep version
    versionCode=1 minSdk=30 targetSdk=34
    versionName=3.0
IWB:/ $

从上面日志看,第一次dumps 这个应用的包名和路径是 system 目录的;
安装系统应用后,重新dumpsys 这个应用的包名和路径是data 目录下的;
说明这个系统应用是安装上去的。还可以查看version 或者time 确认。

另外要注意的是:

在Android Studio编译的apk version版本是在app\build.gradle 里面定义使能的,
AndroidManifest.xml定义是没用的,会被覆盖!

4、Android14 Bluetooth系统蓝牙应用调试

蓝牙应用可能调试的人不多,我之前是偶尔要调试的;
但是发现蓝牙apk应用无法替换,因为Android14 开始有些应用是apex目录下的,无法remount这个目录!
所以一般都是编译整个大包进行调试的;
但是通过上面的知识了解后,发现蓝牙apk是可以直接install的,
以前白走了冤枉路,所以有更多知识储备是很有必要的,虽然有时候不一定马上用得上。

下面就是分析系统蓝牙应用的安装替换过程:

(1)查看蓝牙应用的安装目录
console:/ # dumpsys package com.android.bluetooth | grep path
    path: /apex/com.android.btservices/app/Bluetooth@UP1A.231105.001.B2/Bluetooth.apk

蓝牙apk 居然在apex目录!
这个是从Android14 开发才会这样的,有些模块系统放在了apex目录下;

Android13 或者更低的版本都是放在system或者system_ext目录下的。是可以解锁后替换apk的。

调试发现 apex 目录默认是不开放的,无法解锁替换!

(2)apex目录apk 无法直接替换!
C:\Users\As11040>adb root
restarting adbd as root

C:\Users\As11040>adb remount
Verity is already disabled
Remounted /system as RW
Remounted /system_ext as RW
Remounted /system_dlkm as RW
Remounted /vendor as RW
Remounted /product as RW
Remounted /odm as RW
Remounted /vendor_dlkm as RW
Remounted /odm_dlkm as RW
Remounted /oem as RW
Remount succeeded

C:\Users\As11040>adb shell
IWB:/ # cd /apex/com.android.btservices/app
IWB:/apex/com.android.btservices/app # mkdir aa
mkdir: 'aa': Read-only file system
1|IWB:/apex/com.android.btservices/app #
1|IWB:/apex/com.android.btservices/app # cd ../../..
IWB:/ # cd system/priv-app/
IWB:/system/priv-app # mkdir aa
IWB:/system/priv-app #

上面执行命令代码可以看到即使root和remount,也是无法获取到apex目录的修改权限。
adb push 是试过的,也是报错提示:Read-only file system
没有其他办法的情况,只能编译大包进行调试了。

但是通过上面的persistent知识,获取到了灵感,
感觉可以试试直接install看看是否报错,即使报错也是可以解决的。

####(3)查看蓝牙应用是否是 persistent 应用

系统蓝牙apk应用声明persistent情况:

release\packages\modules\Bluetooth\android\app\AndroidManifest.xml

   <!-- For PBAP Owner Vcard Info -->
    <uses-permission android:name="android.permission.READ_PROFILE"/>
    <application android:name="com.android.bluetooth.btservice.AdapterApp"
         android:icon="@mipmap/bt_share"
         android:persistent="false"
         android:label="@string/app_name"
         android:supportsRtl="true"
         android:usesCleartextTraffic="false"
         android:directBootAware="true"
         android:defaultToDeviceProtectedStorage="true"
         android:memtagMode="async">


这里查看蓝牙应用设置persistent为false,那么应该是可以直接安装的。
如果persistent为true,可以设置为false编译一次,后面就可以一直调试。

尝试直接安装是成功的:

(4)蓝牙应用可以直接install 安装成功
C:\Users\As11040>adb install Bluetooth.apk
Performing Streamed Install
Success

成功了,哈哈。

(5)dumpsys 查看蓝牙应用安装替换情况
console:/ # dumpsys package com.android.bluetooth | grep path
    path: /apex/com.android.btservices/app/Bluetooth@UP1A.231105.001.B2/Bluetooth.apk

console:/ # dumpsys package com.android.bluetooth | grep path
    path: /data/app/~~zptgNMJxOrNyEASJFt3HKg==/com.android.bluetooth-KHInQ7LVcEAHQhjYOSEcJw==/base.apk
console:/ # 

从上面日志看,蓝牙应用确实是从系统应用,变成一个应该普通的install的应用。

这里蓝牙应用 persistent=“false” 是可以直接install 安装的关键。

这里讲解蓝牙只是一个参考,Android14 后面估计还会有很多系统应用会放到apex目录下,
比如nfc等,所以多学掉调试手段是有用的。

5、系统应用设置 persistent=“true” 的作用

确实起到了保活作用,
am force-stop 不会有反应,pid没变;应该是上层拦截了!但是看不到任何相关日志!

kill pid,后应用马上就又被拉起来了。

下面是一些命令调试验证日志:

130|console:/ # 
//(1)查看应用进程情况,包含进程id,父进程,启动时间,应用包名等信息
130|console:/ # ps -eff | grep com.skg.settings
system        6317  5441 0 11:01:28 ?     00:00:02 com.skg.settings

//(2)强制停止应用
console:/ # am force-stop com.skg.settings
console:/ # 
//(3))强制停止后,查看进程信息是没有变化的
console:/ # ps -eff | grep com.skg.settings                                    
system        6317  5441 0 11:01:29 ?     00:00:02 com.skg.settings
console:/ # 
//(4)杀死进程id试试
console:/ # kill 6317
console:/ # 
//(5)杀死进程id后,进程是有重新启动的,会生成新的进程id
console:/ # ps -eff | grep com.skg.settings                       
system       20485  5441 10 11:28:12 ?    00:00:00 com.skg.settings
console:/ # 
//(6)杀死父进程id试试
console:/ # kill 5441
console:/ # 
//(7)杀死进程id后,父进程和进程都会重新生成,系统会黑屏一下,估计是系统上层重启了,
//所以最好不要杀父进程,有可能会导致系统重启,或者无法正常开机,一般断开上电可以恢复
console:/ # ps -eff | grep com.skg.settings
system       24353 23431 41 11:34:08 ?    00:00:01 com.skg.settings
console:/ # 

从上面日志看,
am force-stop 是无法停止应用的;
直接kill进程是可以杀死应用,但是马上就会重启启动新的进程;
所以

如果应用有继承Application,可以看到应用重开拉起来的时候有执行onCreate,可以重新初始化自己需要的东西。

上面说了那么多好像没说怎么从非代码手段判断一个应用是是否是 persistent的系统应用。
其实只要有apk或者运行环境,也是可以判断的。

5、判断应用是否是persistent类型的系统应用

下面从三个维度判断这个应用是否是persistent类型的系统应用,
源码下、应用apk文件、运行环境。

(1)AndroidManifest.xml 代码判断签名和属性
1、查看根目录是否声明了系统签名权限:android:sharedUserId="android.uid.system"
2、查看Application 是否声明了:persistent="true"
(2)应用apk文件反编译分析

apk咋判断?其实就是反编译,查看 AndroidManifest.xml 文件,这个和第一个方式类似。
大部分系统文件都是没有经过复杂混淆的,看AndroidManifest里面的基本信息是没啥问题的。

反编译工具命令就不展示了,其实Android Studio 就可以简单反编译,
把apk拖到一个Studio的项目,就会反编译看到AndroidManifest的内容:

简单示例如下:
uid信息:
在这里插入图片描述

persistent信息:
在这里插入图片描述

上面就相当于看到了源码的整个 AndroidManifest 的信息。
声明的权限、Acitivity和Service那些四大组件信息都是有的,想看啥就看啥。

(3)运行环境dumpsys package分析

dumpsys package 可以看到应用的很多具体信息,
比如签名情况,安装时间,安装路径,版本号,应用获取到的权限等信息,persistent 也是可以看到的。

下面是判断判断过滤appid和persistent的示例日志:

//1、查看系统uid签名的应用appid都是1000;flags里面查看是否有 PERSISTENT 属性
console:/ # 
console:/ # dumpsys package com.dubug.settings | grep -i -E "appid|persistent"
    appId=1000
    flags=[ SYSTEM DEBUGGABLE HAS_CODE PERSISTENT ALLOW_CLEAR_USER_DATA UPDATED_SYSTEM_APP TEST_ONLY ALLOW_BACKUP ]
    pkgFlags=[ SYSTEM DEBUGGABLE HAS_CODE PERSISTENT ALLOW_CLEAR_USER_DATA UPDATED_SYSTEM_APP TEST_ONLY ALLOW_BACKUP ]
    appId=1000
    appId=1000
console:/ # 

//2、查看蓝牙应用,可以看到是不是uid签名,其实是bluetooth签名,也没有PERSISTENT属性
console:/ # dumpsys package com.android.bluetooth | grep -i -E "appid|persistent"
    appId=1002
    appId=1002
    appId=1002
console:/ # 
//3、查看一个普通应用,appId id不是1000,有没有PERSISTENT已经不重要了!
console:/ # dumpsys package com.demo.listdemo | grep -i -E "appid|persistent"
    appId=10070
console:/ # 
console:/ # 
//后面尝试在普通应用加入persistent="true"声明,在apk的flags里面也是未发现有PERSISTENT属性标签,
//说明PERSISTENT属性生效是有一定条件的,比如需要系统签名权限。

6、普通应用设置 persistent=“true” 有用吗?

其实没啥用,我试过了。可以直接安装,,不会安装失败,也不会保活。
这个应该就是 InstallPackageHelper.java里面判断了是否系统应用,否则这个persistent属性没啥意义。

本文只是想说系统应用声明persistent="true"会导致无法直接安装,没想到附带了这么多小知识。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2260697.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

java基础概念49-数据结构2

一、树 1-1、树的基本概念 1、树的节点 2、二叉树 3、树的高度 1-2、二叉查找树 普通二叉树没有规律&#xff0c;不方便查找&#xff0c;没什么作用。 1、基本概念 2、添加节点 此时&#xff0c;该方式添加形成的二叉查找树&#xff0c;根节点就是第一个节点。 3、查找节点 4…

数据仓库工具箱—读书笔记01(数据仓库、商业智能及维度建模初步)

数据仓库、商业智能及维度建模初步 记录一下读《数据仓库工具箱》时的思考&#xff0c;摘录一些书中关于维度建模比较重要的思想与大家分享&#x1f923;&#x1f923;&#x1f923; 博主在这里先把这本书"变薄"~有时间的小伙伴可以亲自再读一读&#xff0c;感受一下…

说说你对java lambda表达式的理解?

大家好&#xff0c;我是锋哥。今天分享关于【说说你对java lambda表达式的理解?】面试题。希望对大家有帮助&#xff1b; 说说你对java lambda表达式的理解? 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 Java Lambda 表达式是 Java 8 引入的一项重要特性&#…

ambari-server页面错位问题解决

背景&#xff1a; 项目新安装的ambari集群页面错位如下 解决办法&#xff08;临时&#xff09;&#xff1a; 修改ambari-server的前端文件&#xff1a;/usr/lib/ambari-server/web/javascripts/app.js 原代码&#xff1a; initNavigationBar: function () {if (App.get(r…

高效数据集成:钉钉与企业系统无缝对接

钉钉数据集成案例分享&#xff1a;鸿巢基础资料-供应商账号(删除操作) 在企业信息化管理中&#xff0c;数据的准确性和及时性至关重要。本文将聚焦于一个具体的系统对接集成案例——钉钉数据集成到钉钉&#xff0c;详细探讨如何通过轻易云数据集成平台实现“鸿巢基础资料-供应…

第六届地博会开幕,世界酒中国菜美食文化节同期启幕推动地标发展

第六届知交会暨地博会开幕&#xff0c;辽黔欧三地馆亮点纷呈&#xff0c;世界酒中国菜助力地理标志产品发展 第六届知交会暨地博会盛大开幕&#xff0c;多地展馆亮点频出&#xff0c;美食文化节同期启幕推动地标产业发展 12月9日&#xff0c;第六届粤港澳大湾区知识产权交易博…

CVMJ 2024 | StyleDiffusion: 基于Prompt嵌入的真实图像反演和文本编辑

论文&#xff1a;《StyleDiffusion: Prompt-Embedding Inversion for Text-Based Editing》 代码&#xff1a;https://github.com/sen-mao/StyleDiffusion​https://github.com/sen-mao/StyleDiffusion​ 问题背景 已有一些工作利用预训练扩散模型进行真实图像的编辑。这些方…

Cisco Packet Tarcer配置计网实验笔记

文章目录 概要整体架构流程网络设备互连基础拓扑图拓扑说明配置步骤 RIP/OSPF混合路由拓扑图拓扑说明配置步骤 BGP协议拓扑图拓扑说明配置步骤 ACL访问控制拓扑图拓扑说明配置步骤 HSRP冗余网关拓扑图拓扑说明配置步骤 小结 概要 一些环境配置笔记 整体架构流程 网络设备互连…

conda学习

参考: Anaconda 官网教程 https://freelearning.anaconda.cloud/get-started-with-anaconda/18202conda配置虚拟环境/conda环境迁移/python环境迁移 https://blog.csdn.net/qq_43369406/article/details/127140839 环境&#xff1a; macOS 15.2Anaconda Navigator 2.4.2 x.1…

C/C++中的宏定义

在C程序中&#xff0c;可以用宏代码提高执行效率。宏代码本身不是函数&#xff0c;但使用起来像函数。预处理器用复制宏代码的方式代替函数调用&#xff0c;省去了参数压栈、生成汇编语言的CALL调用、返回参数、执行return等过程&#xff0c;从而提高了速度&#xff0c;避免函数…

JAVA:访问者模式(Visitor Pattern)的技术指南

1、简述 访问者模式(Visitor Pattern)是一种行为型设计模式,允许你将操作分离到不同的对象中,而无需修改对象本身的结构。这种模式特别适合复杂对象结构中对其元素进行操作的场景。 本文将介绍访问者模式的核心概念、优缺点,并通过详细代码示例展示如何在实际应用中实现…

【安卓开发】【Android Studio】启动时报错“Unable to access Android SDK add-on list”

一、问题描述 在启动Android Studio时&#xff0c;软件报错&#xff1a;Unable to access Android SDK add-on list&#xff0c;报错截图如下&#xff1a; 二、原因及解决方法 初步推测是由于网络节点延迟&#xff0c;无法接入谷歌导致的。点击Cancel取消即可。

安宝特分享 | AR技术助力医院总院与分院间的远程面诊

随着科技的迅猛发展&#xff0c;增强现实&#xff08;AR&#xff09;技术在各行各业的应用愈发广泛&#xff0c;特别是在医疗领域&#xff0c;其潜力和价值正在被不断挖掘。在现代医疗环境中&#xff0c;患者常常面临“看病难、看病远、看病急”等诸多挑战&#xff0c;而安宝特…

Android Studio新版本的一个资源id无法找到的bug解决

Android Studio新版本的一个资源id无法找到的bug解决 文章目录 Android Studio新版本的一个资源id无法找到的bug解决一、前言二、Android Studio的无法获取到资源id的bug1、一段简单的Java代码1、错误现象2、错误解决方法 三、其他1、小结2、gradle.properties文件 其他相关属性…

负载均衡器到底是个啥?

引言 目前在项目中&#xff0c;我们正在使用ELB&#xff08;弹性负载均衡&#xff09;&#xff0c;我希望能够完全理解其内部功能&#xff0c;因此写了这篇文章。 关于本文 这篇文章的最终目标是深刻理解“ELB是什么&#xff1f;”&#xff0c;并达到能够自信解释的程度。 …

远程调试软件对比与使用推荐

远程调试软件对比与使用推荐 远程调试是现代软件开发中不可或缺的一部分&#xff0c;尤其是在处理分布式系统、云端服务或远程服务器上的问题时。以下是对几种常见远程调试工具的详细对比和推荐使用场景。 1. GDB (GNU Debugger) 特点 开源&#xff1a;完全免费且开源&…

【unity】从零开始制作平台跳跃游戏--界面的认识,添加第一个角色!

在上一篇文章中&#xff0c;我们已经完成了unity的环境配置与安装⬇️ 【Unity】环境配置与安装-CSDN博客 接下来&#xff0c;让我们开始新建一个项目吧&#xff01; 新建项目 首先进入unityHub的项目页面&#xff0c;点击“新项目”&#xff1a; 我们这个系列将会以2D平台…

数据结构初阶---二叉树---堆

一、树 1.树的概念 树是一种非线性的数据结构&#xff0c;由n(n≥0)个有限结点组成的一个有层次关系的集合。形状类似一棵倒挂的树&#xff0c;根朝上&#xff0c;分支向下。 根结点没有前驱结点&#xff0c;可以有n(n≥0)个后继结点。 其余结点被分为M个互不相交的集合&am…

1. 机器学习基本知识(3)——机器学习的主要挑战

1.5 机器学习的主要挑战 1.5.1 训练数据不足 对于复杂问题而言&#xff0c;数据比算法更重要但中小型数据集仍然很普遍&#xff0c;获得额外的训练数据并不总是一件轻而易举或物美价廉的事情&#xff0c;所以暂时不要抛弃算法。 1.5.2 训练数据不具有代表性 采样偏差&#…

CentOS 上如何查看 SSH 服务使用的端口号?

我们知道&#xff0c;linux操作系统中的SSH默认情况下&#xff0c;端口是使用22&#xff0c;但是有些线上服务器并不是使用的默认端口&#xff0c;那么这个时候&#xff0c;我们应该如何快速知道SSH使用的哪个端口呢&#xff1f; 1、通过配置文件查看 cat /etc/ssh/sshd_confi…