wallpaper

news/2025/2/21 8:20:53/

设置壁纸

void changeWallpaper(Bitmap targetBitmap) {WallpaperManager wallpaperManager = WallpaperManager.getInstance(context);wallpaperManager.setBitmap(targetBitmap);
}

wallpapermanager和 wallpaperManagerService

WallpaperManager {static WallpaperManager getInstance(Context context) {return context.getSystemService(Context.WALLPAPER_SERVICE);}
}

ContextImpl的getSystemService,最后会调用SystemServiceRegistry.getSystemService(String name)

从ServiceManager获取wallpaperManagerService的binder,缓存到这个Registry里。

SystemServiceRegistry {static {registerService(Context.WALLPAPER_SERVICE, WallpaperManager.class,new CacheServiceFetcher<WallpaperManager>() {WallpaperManager createService(ContextImpl ctx) {IBinder b;b = ServiceManager.getServiceOrThrow(Context.WALLPAPER_SERVICE);IWallpaperManager service = IWallpaperManager.Stub.asInterface(b);return new WallpaperManager(service, ctx.get)}});}static void registerService(String serviceName, Class<T> serviceClass, ServiceFetcher<T> serviceFetcher) {SYSTEM_SERVICE_FETCHERS.put(serviceName, serviceFetcher);}
}

获取时

SystemServiceRegistry {static String getSystemServiceName(Class<?> serviceClass) {return SYSTEM_SERVICE_NAMES.get(serviceClass);}
}

WallpaperMS 向ServiceManager注册自己的binder

class WallpaperManagerService {static class Lifecycle {onStart() {Class klass = Class.forName("com.android.server.wallpaper.WallpaperManagerService");mService = klass.getConstructor(Context.class).newInstance(getContext());//反射创建servicepublishBinderService(Context.WALLPAPER_SERVICE, mService);}}
}

改壁纸接口

WallpaperManager {setBitmap(Bitmap bitmap) {setBitmap(bitmap, null, true);}//最终调到这个。//which = FLAG_SYSTEM| FLAG_LOCK,具体是1<<0和 1<<1setBitmap(Bitmap fullImage, Rect visibleCropHint,boolean allowBackup, @SetWallpaperFlags int which, int userId) {WallpaperSetCompletion completion = new WallpaperSetCompletion();//如名字,监听壁纸设置完成//sGlobal.mService就是WallpapaerManagerService的binder。//参数里没有fullImage。这个方法只是返回了fdParcelFileDescriptor fd = sGlobal.mService.setWallpaper(null, ..., completion, userId);if (fd != null) {FileOutputStream fos = null;fos = new ParcelFileDescriptor.AutoCloseOutputStream(fd);//打开输出流fullImage.compress(.., fos); //把图片保存到输出流里fos.close();completion.waitForCompletion(); //等30ms,设置成功的话,能接收到回调。}}
}

进到wallpaperMS里

WallpaperMS {setWallpaper(String name, ..., int which, ., int userId) { //name=null...WallpaperData wallpaper;wallpaper = getWallpaperSafeLocked(userId, which);// 获取wallpaperData//生成 /data/.../wallpaper 的文件描述符,回传给wallpaperManagerParcelFileDescriptor pfd = updateWallpaperBitmapLocked(name, wallpaper, extras);...return pfd;}
}

获取WallpaperData

WallpaperMS {WallpaperData getWallpaperSafeLocked(int userId, int which) {SparseArray<WallpaperData> whichSet = (which == FLAG_LOCK) ? mLockWallpaperMap : mWallpaperMap;WallpaperData wallpaper = whichSet.get(userId);//如果wallpaper是null,重新load一次,如果load后还是获取不到,新建wallpaperData并保存...return wallpaper;}
}

wallpaperMS生成文件描述符,用于返回给wallpaperManager

WallpaperMS {ParcelFileDescriptor updateWallpaperBitmapLocked(String name, WallpaperData wallpaper,Bundle extras) {ParcelFileDescriptor fd = ParcelFileDescriptor.open(wallpaper.wallpaperFile, MODE_CREATE | MODE_READ_WRITE | MODE_TRUNCATE); // 创建/data/../wallpaper文件的描述符wallpaper.wallpaperId = makeWallpaperIdLocked();// id + 1return fd;}
}

WallpaperManager监听壁纸设置完成

WallpaperManager {//这个IWallpaperManagerCallback.aidl中,原生里只有一个借口:onWallpaperChanged()class WallpaperSetCompletion extends IWallpaperManagerCallback.Stub {CountDownLatch mLatch;void waitForCompletion() {mLatch.await(30, TimeUnit.SECONDS);//本线程park,30s超时}//完成的话,能接收到WallpaperMS的回调@Overridevoid onWallpaperChanged() {mLatch.countDown(); //设置完成时,由binder线程回调,unpark本线程}}
}

CountDownLatch的原理

使用aqs实现的,为了保证线程同步。1,调用CountDownLetch.await(long timeout, TimeUnit unit)时,获取int state,想要的state是0,但此时是1。
所以生成一个Node,保存当前的Thread。并park当前thread。2,其他线程调用CountDownLetch的countDown时,compareAndSetState(1, 0),把state设置为0。并从Node链表中取出距离head最近的node,获取node中保存的thread,并unpark.

WallpaperMS发送壁纸设置完成的消息

系统启动到third_party apps can start阶段,会调用switch(UserHandle.USER_SYSTEM, null)。
然后创建wallpaperData.wallpaperObserver,并启动监听

WallpaperMS {switch(int userId, IRemoteCallback reply) {WallpaperData systemWallpaper;...systemWallpaper = getWllpaperSafeLocked(userId, FLAG_SYSTEM);// 创建observer,并启动监听if (systemWallpaper.wallpaperObserver == null) {systemWallpaper.wallpaperObserver = new WallpaperObserver(systemWallpaper);systemWallpaper.wallpaperObserver.startWatching();}}
}

如何监听的?

WallpaperMS {class WallpaperObserver extends FileObserver {//监听/data/../0/这个目录下所有文件WallpaperObserver(WallpaperData wallpaper) {super(getWallpaperDir(wallpaper.userId).getAbsolutePath(),CLOSE_WRITE | MOVED_TO | DELETE | DELETE_SELF);...}super.startWatching() {}}
}

加载wallpaperData.

时机:系统AMS ready时,通过SystemServiceManager告诉各个SystemService,接口是onBootPhase(int)。

WallpaperMS {loadSettingsLocked(int userId, boolean keepDimensionHints) {...WallpaperData wallpaper = mWallpaperMap.get(userId);if (wallpaper == null) {wallpaper = new WallpaperData(userId, WALLPAPER, WALLPAPER_CROP);mWallpaperMap.put(userId, wallpaper); //创建个新的data,保存到map里if (!wawllpaper.cropExists()) {if (wallpaper.sourceExist()) {//如果/data/system/users/0/中,只有wallpaper_orig文件,没有wallpaper文件,则生成generateCrop(wallpaper);}}}//解析/data/system/users/0/wallpaper_info.xml文件//解析到mWallpaperMap的wallpaperData里,component是第三发软件。//解析到mDisplayDatas的DisplayData里保证wallpaperData和displayData中的显示区域,至少是Display的长边长度}
}

system*service*等类

abstrat class SystemService {public static final int PHASE_WAIT_FOR_DEFAULT_DISPLAY = 100;...public static final int PHASE_BOOT_COMPLETED = 1000;void onBootPhase(int phase) {}
}

ServiceManager 通过jni注册binder

SystemServer 使用SystemServiceManager启动各个SystemService

SystemServiceManager 用于管理各个SystemService,创建它们、启动它们、保存它们、通知它们的各个状态

SystemService 对应了各个服务(ams、pms..),抽象出了几个接口(onBootPhase\ onStart\ onUserStart\ onUserSwitch\ onUnlockUser...)这些状态被SystemServiceManager回调。

SystemServiceRegistry 是app端的缓存,保存了name 和 各种serviceManager,serviceManager里持有service的binder


http://www.ppmy.cn/news/282727.html

相关文章

Archlinux安装动态墙纸(fantascene-dynamic-wallpaper)软件。

1.进入archlinux官网的AUR (en) - Home&#xff1a; 2.输入如下内容开始搜索软件包&#xff08;fantascene-dynamic-wallpaper&#xff09; 3.点击第一个&#xff0c;复制链接。 4.在终端输入如下命令下载软件包。 命令&#xff1a;git clone https://aur.archlinux.org/fanta…

适配器模式的运用

文章目录 一、适配器模式的运用1.1 介绍1.2 适配器模式结构1.3 类适配器模式1.3.1 类适配器模式类图1.3.2 代码 1.4 对象适配器模式1.4.1 对象适配器模式类图1.4.2 代码 1.5 应用场景1.6 JDK源码解析1.6.1 字节流到字符流的转换类图1.6.2 部分源码分析1.6.3 总结 一、适配器模式…

推荐一款比Flink CDC更好用的免费CDC工具

很多中大型企业都希望选择一款足够轻量好用的CDC工具&#xff0c;而且最好是小白用户都能使用的CDC工具&#xff0c;今天就推荐一款小白都能安装并立即使用的CDC工具给大家。 CDC&#xff08;Change Data Capture&#xff09;是一种用于捕获和传递数据库实时变更的技术。它允许…

如何用新范式解决安全难题?数字安全免疫力研讨论坛给你答案!

6月13日&#xff0c;腾讯安全、腾讯研究院将联动IDC、《中国信息安全》杂志社、CIO 时代、新基建创新研究院等多家行业机构、媒体共同发起「数字安全免疫力」研讨论坛&#xff0c;汇聚产学研各界专家&#xff0c;研判安全态势、分享最佳实践&#xff0c;碰撞新一代的安全理念&a…

单片机定时音乐播放器

功能&#xff1a; 矩阵键盘输入定时&#xff0c;Enter键确认&#xff0c;Clear键清零&#xff1b; 定时结束后自动停止&#xff0c;End键可提前停止。 工具&#xff1a; Proteus、Keil。 原理图&#xff1a; 源代码&#xff1a; #include <reg51.h>/**定义音符频率*…

C51语言编程基础

C51语言编程基础 Keil C51语言基础知识 关键字 关键字用途说明bit位标量声明声明一个位标量或位类型的函数sbit位标量声明声明一个可位寻址变量sfr特殊功能寄存器声明声明一个特殊功能寄存器sfr16特殊功能寄存器声明声明一个16位的特殊功能寄存器data存储器类型说明直接寻址…

【JD算法题】定义一个数组的权值为,该数组最大值的出现次数。求长度为n且每个元素范围都在[1,n]的所有数组的权值之和。

Problem 小红定义一个数组的权值为&#xff0c;该数组最大值的出现次数。 例如[2,3,3,4]的权值为1&#xff0c;[2,3,3,3]的权值为3. 小红想知道&#xff0c;长度为n&#xff0c;且每个元素范围都在[1,n]的数组&#xff08;显然有n^n个数组&#xff09;&#xff0c;这些数组的权…

Keil 5 C51与STM32

Keil安装以及破解 链接&#xff1a;https://pan.baidu.com/s/1ZNSFUBD6q6pEixHx6spjmw 提取码&#xff1a;xf85 安装方法按照txt文档说明进行&#xff0c;以下为早期版本安装方法&#xff0c;仅供参考 选择安装地址 完善信息&#xff08;这个地方随便写&#xff09; 以管理…