wallpaper_md

设置壁纸

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());//反射创建service
            publishBinderService(Context.WALLPAPER_SERVICE, mService);
        }
    }
}

改壁纸接口

WallpaperManager {
	setBitmap(Bitmap bitmap) {
        setBitmap(bitmap, null, true);
    }

    //最终调到这个。
    //which = FLAG_SYSTEM| FLAG_LOCK,具体是1<<0和 1<<1
    setBitmap(Bitmap fullImage, Rect visibleCropHint,
            boolean allowBackup, @SetWallpaperFlags int which, int userId) {
        

        WallpaperSetCompletion completion = new WallpaperSetCompletion();//如名字,监听壁纸设置完成

        //sGlobal.mService就是WallpapaerManagerService的binder。
        //参数里没有fullImage。这个方法只是返回了fd
        ParcelFileDescriptor 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 的文件描述符,回传给wallpaperManager
        ParcelFileDescriptor 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 + 1
        return fd;
    }
}

WallpaperManager监听壁纸设置完成

WallpaperManager {
    //这个IWallpaperManagerCallback.aidl中,原生里只有一个借口:onWallpaperChanged()
    class WallpaperSetCompletion extends IWallpaperManagerCallback.Stub {
        CountDownLatch mLatch;

        void waitForCompletion() {
            mLatch.await(30, TimeUnit.SECONDS);//本线程park,30s超时
        }

        //完成的话,能接收到WallpaperMS的回调
        @Override
        void 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的长边长度
}

}

systemservice等类

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

​# 壁纸文件变化的监听
wms 初始化时,调用switchUser()创建WallpaperObserver,用于监听壁纸目录下文件的变化。

class WMS {
    void switchUser(..) {
        if (systemWallpaper.wallpaperObserver == null) {
                systemWallpaper.wallpaperObserver = new WallpaperObserver(systemWallpaper);
                systemWallpaper.wallpaperObserver.startWatching();
        }
    }
}

监听的是壁纸目录里的文件

class WallpaperMS {
    class WallpaperObserver extends FileObserver {
        WallpaperObserver(WallpaperData wallpaper) {
            super(getWallpaperDir(wallpaper.userId).getAbsolutePath(), .);//监听目录保存到mFiles里
        }
    }
}

FileObserver监听文件变化

class FileObserver {
    //启动监听线程
    static {
        s_observerThread = new ObserverThread();
        s_observerThread.start();
    }

    List<File> mFiles; //保存要监听的文件

    //开始监听指定的文件
    void startWatch() {
        mDescriptors = s_observerThread.startWatching(mFiles, mMask, this); //一个进程里,只有一个s_observerThread
    }

    static class ObserverThread extends Thread {
        int m_fd; //调用native int init()方法获取的,是inotify实例的fd,inotify是kernal层实现监听文件变化的方式。

        void run() {
            observe(m_fd); //native方法,android_util_FileObserver.cpp里,开始阻塞监听inofity的变化。
        }

        //开始监听指定文件
        int[] startWatching(List<File> files, ., FileObserver observer) {
            String[] paths; //把files转成路径

            int[] wfds = new int[count]; //类似于要监听文件的id
            
            startWatching(m_fd, paths, ., wfds); //native方法,传入要监听的文件路径给inotify。如果要监听的文件有变,则inotify会有消息。上面的observer就读取到变化,最后通过native方法onEvent()回调回来

            m_observers.put(wfd, observer);

            return wfds;
        }

        //文件变化->inotify变化->observer监听阻塞被唤醒 ->调到这
        onEvent(...) {
            从m_observers里取出observer来,回调
        }
    }

}

WMS里接收到文件变化

WMS {
    class WallpaperObserver {
        onEvent(int event, String path) {

            if (sysWallpaperChanged || lockWallpaperChanged) {//根据path,判断是哪个壁纸文件变化了
                ...

                if (wallpaper.wallpaperComponent == null //壁纸软件的componentName
                            || event != FileObserver.CLOSE_WRITE 
                            || wallpaper.imageWallpaperPending) {
                    ...

                    if (written) { //文件写完并close了,或者有文件被移动到被监听目录
                        ...

                        if (wallpaper.setComplete != null) {
                            wallpaper.setComplete.onWallpaperChanged(); //这个就是wallpaperManager传过来的binder。
                        }
                    }
                }
            }
        }
    }
}

wm中,setBitmap来设置壁纸

WMS中,setWallpaper来获取要修改壁纸的fd

WMS {
    //没有直接修改文件,而是返回了要修改壁纸的 文件描述符
    ParcelFileDescriptor setWallpaper(String name, ..., int which, IWallpaperManagerCallback completion, int userId) {
        ...
        wallpaper = getWallpaperSafeLocked(userId, which);
        ParcelFileDescriptor pfd = updateWallpaperBitmapLocked(name, wallpaper, extras); //生成fd
        wallpaper.setComplete = completion;

        return pfd;
    }
}

获取要修改壁纸的文件描述符

WMS {
    ParcelFileDescriptor updateWallpaperBitmapLocked(String name, WallpaperData wallpaper, Bundle extras) {
        ...
        ParcelFileDescriptor fd = ParcelFileDescriptor.open(wallpaper.wallpaperFile, 
                    MODE_CREATE|MODE_READ_WRITE|MODE_TRUNCATE); //本质是根据path和mode,生成fd
        ...
        return fd;
    }
}

SystemUi端怎么知道壁纸改变了?

XxImageWallpaper {

}

壁纸怎么显示出来的?

wms接收到系统启动的phase third party apps can start 阶段,执行switchUser。
其中,不仅创建wallpaperObserver监听文件夹变化。
还执行switchWallpaper(systemWallpaper, reply)来连接wallpaperService

WMS {
    switchUser(int userId, .) {
        systemWallpaper.wallpaperObserver = new WallpaperObserver(systemWallpaper);
        ...
        switchWallpaper(systemWallpaper, reply);
    }
}

计算要绑定哪个service。默认是systemUI的ImageWallpaper,如果设置为了第三方app当做壁纸,则会修改这个component。

WMS {
    switchWallpaper(WallpaperDzta wallpaper, .) {
        //wallpaper.nextWallpaperComponent 在WMS启动时,loadSettingsLock中,被赋值为mImageWallpaper,是写在xml中的,内容是systemUI的那个ImageWallpaper
        ComponentName cname = 先取wallpaper.wallpaperComponent;如果是null,则取wallpaper.nextWallpaperComponent;

        if (!bindWallpaperComponentLocked(cname, true, false, wallpaper, .)) { //取bind service

        }
    }
}

绑定wallpaperData中的wallpaperComponent指向的service

WMS {
    boolean bindWallpaperComponentLocked(ComponentName componentName, ...) {
        ServiceInfo si = mIPackageManager.getServiceInfo(componentName, ..); //获取ImageService的信息。

        WallpaperInfo wi = null;

        if (component != null && !component.equals(mImageWallpaper)) {//如果不是systemUI的那个ImageService
            ...
        }

        int componentUid = MIPackageManager.getPackageUid(componentName.getPackageName(), ., wallpaper.userId);

        //用systemUI.imageService时,wi是null。
        //componentUid 是app的uid
        WallpaperConnection newConn = new WallpaperConnection(wi, wallpaper, componentUid);

        //intent.mAction="android.service.wallpaper.WallpaperService"
        //intent.mComponent=componentName,imageService所在的componentName
        if (!mContext.bindServiceAsUser(intent, newConn, ..)) { 

        }

        ...
        if (wallpaper.userId == mCurrentUserId && mLastWallpaper != null
                && !wallpaper.equals(mFallbackWallpaper)) {
            detachWallpaperLocked(mLastWallpaper);//会执行 mContext.unbindService(wallpaper.connection)
        }
        ...
    }
}

systemUI的ImageService被启动,返回IBinder。

XxImageWallpaper extends ImageWallpaper extends WallpaperService {
    IBinder onBind(Intent intent) {
        return new IWallpaperServiceWrapper(this); // 2个binder接口,attach\ detach
    }
}

链接ImageService的类。

WMS {
    class WallpaperConnection extends IWallpaperConnection.Stub implements ServiceConnection {
        onServiceConnected(ComponentName name, IBinder service) {
            if (mWallpaper.connection == this) {
                mService = IWallpaperService.Stub.asInterface(service); //获得ImageService端的binder
                attachServiceLocked(this, mWallpaper); //执行 DisplayConnector的connectLocked(),connector一般就是defaultDisplayId一个。

                //还会保存WallpaperData到文件里。
                ...
            }
        }
    }
}

交给DisplayConnector来连接

WMS {
    class WallpaperConnection {
        class DisplayConnector {
            connectLocked(WallpaperConnection connection, WallpaperData wallpaper) {
                connection.mService.attach(connection, mToken, ...); //把connection回传给systemUI.imageService
            }
        }
    }
}

systemUI.imageService接收到binder回调。

WallpaperService extends Service {
    class IWallpaperServiceWrapper extends IWallpaperService.Stub { //这个binder被传给wms,wms回调attach方法
        attach(IWallpaperConnection conn, ...) {
            mEngineWrapper = new IWallpaperEngineWrapper(., conn, ...);
        }
    }
}

systemUI的IWallpaperEngineWrapper 来处理conn。把自己(IWallpaperEngineWrapper)传给conn

WallpaperService {
    class IWallpaperEngineWrapper extends IWallpaperEngine.Stub {
        IWallpaperEngineWrapper(WallpaperService context, IWallpaperConnection conn, ...) {
            mConnection = conn;
            ...
            //发给SystemUI的主线程来处理
            Message msg = mCaller.obtainMessage(DO_ATTACH);
            mCaller.sendMessage(msg);
        }

        //做了个封装,这里处理
        void executeMessage(Message m) {
            case DO_ATTACH: {
                mConnection.attachEngine(this, mDisplayId); //把自己(IWallpaperEngineWrapper)传给conn

                Engien engine = onCreateEngine(); //创建Engine
                mEngine = engine;
                engine.attach(this); //*这里应该是绘制壁纸的地方*
            }
        }
    }
}

总结一下,WMS和WallpaperService之间相互持有的关系

  1. WMS启动WallpaperService后,
    WMS.WallpaperConnection.mService = WallpaperService.IWallpaperServiceWrapper extends IWallpaperService.Stub

  2. WMS.WallpaperConnection.mService调用IWallpaperService的attach接口,将WMS.WallpaperConnection传给WallpaperService。
    WallpaperService.IWallpaperEngineWrapper.mConnection = WMS.WallpaperConnection extends IWallpaperConnection.Stub

  3. WallpaperService.IWallpaperEngineWrapper.mConnection 调用attachEngine()接口,将WallpaperService.IWallpaperEngineWrapper传给WMS
    WMS.WallpaperConnection.DisplayConnector.mEngine = WallpaperService.IWallpaperEngineWrapper extends IWallpaperEngine.Stub

engine绘制壁纸

WallpaperService{
    class Engine {
        void attach(IWallpaperEngineWrapper wrapper) {
            mConnection = wrapper.mConnection;

            mSession = WindowManagerGlobal.getWindowSession(); //mSession是通过WindowMS获取的Session,用来跟WindowMS通信
            mWindow.setSession(mSession); //mWindow是本类里创建的,是IWindow.Stub 的子类,用于WindowMS告诉app端windowFocusChanged等信息

            onCreate(mSurfaceHolder); //自己的状态回调函数,ImageWallpaper.GLEngine里有具体实现。用于创建ImageWallpaperRenderer。

            updateSurface(false, false, false);
        }
    }
}

#创建surface, WallpaperService获取到WindowMS创建的Surface

WallpaperService {
    class Engine {
        void updateSurface(...) {
            if (...|| creating || ...) {
                try {
                    if (!mCreated) {
                        if (mSession.addToDisplay(mWindow, ..., mInputChannel, .) < 0) {
                            //<0 表示添加失败
                            return;
                        }
                        mCreated = true;
                    }

                    int relayoutResult = mSession.relayout(mWindow, ..., mSurfaceControl, .);
                    if (mSurfaceControl.isValid()) {
                        mSurfaceHolder.mSurface.copyFrom(mSurfaceControl); //surfaceControl里持有surface的long mNativeObject。这里是把SurfaceControl.mNativeObject传给Surface
                        mSurfaceControl.release();
                    }

                    if (!mSurfaceHolder.mSurface.isValid()) {//检查一遍,surface不可用就return
                        return;
                    }


                    try {
                        if (surfaceCreating) {
                            onSurfaceCreated(mSurfaceHolder); //子类ImageWallpaper里的GLEngine会有这个方法的实际实现。
                        }
                    }
                }
                
            }
        }
    }
}

ImageWallpaper.GLEngine extends WallpaperService.Engine 中,使用ImageWallpaperRenderer来显示壁纸

ImageWallpaper {
    class GLEngine {
        GLWallpaperRenderer mRenderer;

        onSurfaceCreated(SurfaceHolder holder) {
            mWorker.getThreadHandler() //mWorker就是个HandlerThread。异步线程
                .post(
                    () -> {
                        mEglHelper.init(holder); //holder里保存了surface,使用这个surface,创建EGLSurface并保存到EglHelper里
                        mRenderer.onSurfaceCreated(); //mRenderer是ImageWallpaperRenderer,在onCreate里就创建了。
                    }
                )
        }
    }
}
ImageWallpaperRenderer implements GLWallpaperRenderer {
    void onSurfaceCreated() {
        if (!loadBitmap()) { //加载
        } else {

        }
        mWallpaper.setup(mBitmap); //把壁纸bitmap,保存到ImageGLWallpaper mWallpaper中。是以int mTextureId来保存的地址
    }
}

从WallpaperManager中,取壁纸

ImageWallpaperRenderer {
    boolean loadBitmap() {
        if (mWallpaperManager != null && mBitmpa == null) {
            mBitmpa = mWallpaperManager.getBitmap(); //从WallpaperManager中取
        }
        ...
        return mBitmap;
    }
}

renderer 持有bitmap,可以画壁纸
mEglHelper 持有surface。
这2者之间,有个共同的参数 EGL14.EGL_DEFAULT_DISPLAY = 0;通过这个参数,可以获取同一个EGLDisplay。
WMS通过IWindow,用接口resized,触发draw行为。最后到Engine.drawFrame()

ImageWallpaper {
    class GLEngine {
        requestRendererInternal() {
            if (readyToRender) {
                //从这2个代码看。是render把bitmap绘制到buffer里,eglHelper把buffer交给SurfaceFlinger去画出来
                mRenderer.onDrawFrame();
                if (!mEglHelper.swapBuffer());
            }
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值