Android Overlay机制总结

Posted 彼天

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android Overlay机制总结相关的知识,希望对你有一定的参考价值。

参考博客,很详细,值得一看,查看点击

背景

车机整机开发有主题壁纸商店。需要满足动态切换资源。选择使用overlay机制实现。和手机上不同的是,使用主题后,指定的所有应用内的资源都需要替换。

效果

video-overlay


通过了解,overlay机制比较适合,不需要去改变目标应用本身的结构。不同主题只需要添加不同的主题apk 就行。

实现步骤

  1. 制作主题apk,overlay项目。
  2. 应为overlay项目只能配置一个目标,需要fw层作出对应修改。
  3. fw层 设置主题apk 生效和失效。

制作Overlay项目

目录结构

里面只有资源文件,无代码。需要系统签名。当然资源文件名称,要和目标项目资源名称一致。
清单文件配置

添加overlay 标签,制定目标应用包名。更多标签内容介绍,可以详细百度。这样Overlay apk 就做好了。

安装好之后,可以用命令查看 adb shell dumpsys overlay
mIsEnabled 是false ,目前还没有生效,生效和失效的adb命令:
adb shell cmd overlay enable com.example.themoverlaydemo
adb shell cmd overlay disable com.example.themoverlaydemo

启动后mIsEnabled 就会变成true。接收命令的类是OverlayManagerShellCommand,路径/homeframeworks/base/services/core/java/com/android/server/om

FW层对应的修改

  1. 配置需要生效的目标应用包名
    frameworks/base/core/res/res/values/arrays.xml 添加目标包名
    <string-array translatable="false" name="config_xxxxxtargetpackages">
        <item>com.android.systemui</item>
        <item>com.android.launcher</item>
        <item>com.xxxxx.appanel</item>
        <item>com.xxxxx.themestore</item>
        <item>com.xxxxx.media</item>
        <item>com.xxxxx.aircondition</item>
        <item>com.android.systemui.plugin</item>
    </string-array>

frameworks/base/core/res/res/values/symbols.xml 中添加array名称

  <java-symbol type="array" name="config_simbatargetpackages" />
  1. OverlayManagerService 设置目标列表
public OverlayManagerService(@NonNull final Context context,
            @NonNull final Installer installer) 
        super(context);
        mSettingsFile =
            new AtomicFile(new File(Environment.getDataSystemDirectory(), "overlays.xml"), "overlays");
        mPackageManager = new PackageManagerHelper();
        mUserManager = UserManagerService.getInstance();
        //获取配置的目标列表
        mSimbaOverlayTarget = new ArrayList<String>(Arrays.asList(context.getResources().getStringArray(
            com.android.internal.R.array.config_simbatargetpackages)));
        IdmapManager im = new IdmapManager(installer);
        mSettings = new OverlayManagerSettings();
        mImpl = new OverlayManagerServiceImpl(mPackageManager, im, mSettings,
                getDefaultOverlayPackages(), new OverlayChangeListener());
        //把目标设置给代理        
        mImpl.setROMTargetPackages(mSimbaOverlayTarget);
        mInitCompleteSignal = SystemServerInitThreadPool.get().submit(() -> 
            final IntentFilter packageFilter = new IntentFilter();
            packageFilter.addAction(ACTION_PACKAGE_ADDED);
            packageFilter.addAction(ACTION_PACKAGE_CHANGED);
            packageFilter.addAction(ACTION_PACKAGE_REMOVED);
            packageFilter.addDataScheme("package");
            // 安装包广播
            getContext().registerReceiverAsUser(new PackageReceiver(), UserHandle.ALL,
                    packageFilter, null, null);

            final IntentFilter userFilter = new IntentFilter();
            userFilter.addAction(ACTION_USER_ADDED);
            userFilter.addAction(ACTION_USER_REMOVED);
            //用户广播
            getContext().registerReceiverAsUser(new UserReceiver(), UserHandle.ALL,
                    userFilter, null, null);

            restoreSettings();
            mImpl.initTargetCodeBasePath();
            initIfNeeded();
            onSwitchUser(UserHandle.USER_SYSTEM);

            publishBinderService(Context.OVERLAY_SERVICE, mService);
            publishLocalService(OverlayManagerService.class, this);
        , "Init OverlayManagerService");
    

先获取配置的目标列表,然后设置给OverlayManagerServiceImpl,这个类坐了很多操作。并且上面注册了包安装的广播,和用户切换的广播。

  1. 设置生效或失效Overlay Apk
private final class PackageReceiver extends BroadcastReceiver 
        @Override
        public void onReceive(@NonNull final Context context, @NonNull final Intent intent) 
            //----省略
            switch (intent.getAction()) 
                case ACTION_PACKAGE_ADDED:
                //升级和add应用包
                    if (replacing) 
                        onPackageUpgraded(packageName, userIds);
                     else 
                        onPackageAdded(packageName, userIds);
                    
                    break;
                case ACTION_PACKAGE_CHANGED:
                    onPackageChanged(packageName, userIds);
                    break;
                case ACTION_PACKAGE_REMOVED:
                    if (replacing) 
                        onPackageUpgrading(packageName, userIds);
                     else 
                        onPackageRemoved(packageName, userIds);
                    
                    break;
                default:
                    // do nothing
                    break;
            
        

        private void onPackageAdded(@NonNull final String packageName,
                @NonNull final int[] userIds) 
            //----省略
                        if (pi.isOverlayPackage()) 
                        //调用OverlayManagerServiceImpl
                            mImpl.onOverlayPackageAdded(packageName, userId);
                         else 
                            mImpl.onTargetPackageAdded(packageName, userId);
                        
                    
                
            
        

我想在安装成功后就让他生效,调用到OverlayManagerServiceImpl 的onOverlayPackageAdded方法

    void onOverlayPackageAdded(@NonNull final String packageName, final int userId) 
       //-----省略
       //通过安装的overlay apk 获取包信息
       final PackageInfo overlayPackage = mPackageManager.getPackageInfo(packageName, userId);
        if (overlayPackage == null) 
            Slog.w(TAG, "overlay package " + packageName + " was added, but couldn't be found");
            onOverlayPackageRemoved(packageName, userId);
            return;
        
       //获取目标包,需要做处理,如果是自己的overlay apk 就返回配置的目标列表
	final ArrayList<String> overlayTargets = getOverlayTargetList(overlayPackage);
	if (isXXXXOverlayApk(packageName)) 
		//如果之前设置了自己的一款主题,先disable
		filterOutAndDisableOverlayForXXXXTargetApp(packageName, overlayTargets, userId);
	
	for (String overlayTarget: overlayTargets) 
	    //遍历目标初始化生成idmap映射
		mSettings.init(packageName, userId, overlayTarget,
		        overlayPackage.applicationInfo.getBaseCodePath(),
		        overlayPackage.isStaticOverlayPackage(), overlayPackage.overlayPriority,
		        overlayPackage.overlayCategory);
	
		if (isXXXXOverlayApk(packageName)) 
				//如果安装的是自己的主题包,就直接设置生效		
                  mSettings.setEnabled(packageName, overlayTarget, userId, true);
		
		 try 
			 if (updateState(overlayTarget, packageName, userId, 0)) 
			     mListener.onOverlaysChanged(overlayTarget, userId);
			
		 catch (OverlayManagerSettings.BadKeyException e) 
			Slog.e(TAG, "failed to update settings", e);
			mSettings.remove(packageName, userId);
		
	
    

当安装了包之后,先获取主题包信息,并获取目标列表,如果是自己开发的主题包,先取消原来的,再设置新的生效。
获取目标列表:

   private ArrayList<String> getOverlayTargetList(PackageInfo overlayPackage) 
	 final ArrayList<String> overlayTarget = new ArrayList<>();
        if (isXXXXOverlayApk(overlayPackage.packageName)) 
        // 自己的主题包,就返回配置目标的列表
            overlayTarget.addAll(mXXXXOverlayTarget);
         else 
            overlayTarget.add(overlayPackage.overlayTarget);
        
	  return overlayTarget;
    

取消原来的:

 private void filterOutAndDisableOverlayForXXXXTargetApp(String overlayPackageName,
		ArrayList<String> simbaTargets, final int userId) 
        for (String simbaTarget : simbaTargets) 
		Slog.d(TAG, "filter out check target name " + simbaTarget);
		List<OverlayInfo> overlayInfos = mSettings.getOverlayByTargetName(overlayPackageName, simbaTarget, userId);
		if (overlayInfos == null) 
		    continue;
		
		Slog.d(TAG, "filter out results " + overlayInfos.size());
		for (OverlayInfo oi: overlayInfos) 
       	    Slog.d(TAG, "to change disable  " + oi.packageName + " - " + oi.targetPackageName + " " +oi.isEnabled());
       	    if (oi.isEnabled()) 
       		mSettings.setEnabled(oi.packageName, oi.targetPackageName, userId, false);
			mSettings.setState(oi.packageName, oi.targetPackageName, userId, OverlayInfo.STATE_DISABLED);
       	    
		
        
    

至此就大功告成。应用升级、删除这些也都需要对应的处理。原理和流程,可以看看文章最开始的链接,写的很不错,点赞。

以上是关于Android Overlay机制总结的主要内容,如果未能解决你的问题,请参考以下文章

Android Overlay机制总结

Android Gradle 插件AaptOptions 配置 ⑥ ( Overlay 重叠包机制 | AaptOptions#additionalParameters 附加参数配置 )

Android Gradle 插件AndroidSourceSets 配置 ① ( Overlay 重叠包机制 | 使用 sourceSets 配置多个 res 目录 )

Android签名验证与反调试机制的对抗技术

Android签名验证与反调试机制的对抗技术

工作日报 2022.4.19 PackageManagerService 扫描APK目录