android 8.1平台默认壁纸设置流程

时间:2022-03-23 18:17:30
开机设置默认壁纸流程
在SystemServer.java中startOtherServices()方法启动mSystemServiceManager.startService(WALLPAPER_SERVICE_CLASS);
启动的是WallpaperManagerService里面的Lifecycle,Lifecycle继承SystemService,WallpaperManagerService继承IWallpaperManager.Stub
查看onStart()方法,里面新建了mService = new WallpaperManagerService(getContext());,然后publishBinderService(Context.WALLPAPER_SERVICE, mService);
接着看WallpaperManagerService的构造方法
public WallpaperManagerService(Context context) {
        if (DEBUG) Slog.v(TAG, "WallpaperService startup");
        mContext = context;
        mShuttingDown = false;
        //com.android.systemui/com.android.systemui.ImageWallpaper 获取ImageWallpaper实例
        mImageWallpaper = ComponentName.unflattenFromString(context.getResources().getString(R.string.image_wallpaper_component));  
        //返回值为null
        mDefaultWallpaperComponent = WallpaperManager.getDefaultWallpaperComponent(context);
        // 获取WindowManagerService的实例
        mIWindowManager = IWindowManager.Stub.asInterface(ServiceManager.getService(Context.WINDOW_SERVICE));
        mIPackageManager = AppGlobals.getPackageManager();
        mAppOpsManager = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
        mMonitor = new MyPackageMonitor();
        mMonitor.register(context, null, UserHandle.ALL, true);
        //获取并新建路径/data/system/users/0
        getWallpaperDir(UserHandle.USER_SYSTEM).mkdirs();


        // Initialize state from the persistent store, then guarantee that the
        // WallpaperData for the system imagery is instantiated & active, creating
        // it from defaults if necessary.
        //下文重点分析(USER_SYSTEM = 0)
        loadSettingsLocked(UserHandle.USER_SYSTEM, false);
        getWallpaperSafeLocked(UserHandle.USER_SYSTEM, FLAG_SYSTEM);


        mColorsChangedListeners = new SparseArray<>();
    }
   
    查看loadSettingsLocked()方法,如注释说明,先在永久区域中初始化状态,然后保证WallpaperData已经实例化和激活
    private void loadSettingsLocked(int userId, boolean keepDimensionHints) {
         //用JournaledFile这个工具类封装/data/system/users/0/wallpaper_info.xml文件。这个工具类会包装两个文件,一个是wallpaper_info.xml正式文件,另一个是 wallpaper_info.xml.tmp临时文件。如果正式文件存在就选出正式文件,并删除临时文件;如果正式文件不存在就将临时文件重名为正式文件。
        JournaledFile journal = makeJournaledFile(userId);
        `````
        if (wallpaper == null) {
            // Do this once per boot
            migrateFromOld();
            //创建一个WallpaperData并存入mWallpaperMap ,我们可以看看WallpaperData 的构造函数,这是一个内部类:
            wallpaper = new WallpaperData(userId, WALLPAPER, WALLPAPER_CROP);
            wallpaper.allowBackup = true;
            mWallpaperMap.put(userId, wallpaper);
        }
        boolean success = false;
        try {
            stream = new FileInputStream(file);
            XmlPullParser parser = Xml.newPullParser();
            parser.setInput(stream, StandardCharsets.UTF_8.name());
           ```````//第一次启动时,wallpaer_info.xml不存在,也就不采用其里面的值。这时,则采用的是getMaximumSizeDimension,也就是背景图的宽和高由getMaximumSizeDimension决定。
        } catch (FileNotFoundException e) {
            Slog.w(TAG, "no current wallpaper -- first boot?");
        } 
        ``````
        ensureSaneWallpaperData(wallpaper);
        ``````
    }


    private void ensureSaneWallpaperData(WallpaperData wallpaper) {
        // We always want to have some reasonable width hint.
        int baseSize = getMaximumSizeDimension();
        if (wallpaper.width < baseSize) {
            wallpaper.width = baseSize;
        }
        if (wallpaper.height < baseSize) {
            wallpaper.height = baseSize;
        }
        // and crop, if not previously specified
        if (wallpaper.cropHint.width() <= 0
                || wallpaper.cropHint.height() <= 0) {
            wallpaper.cropHint.set(0, 0, wallpaper.width, wallpaper.height);
        }
    }
分析到这里,我们看到,除了创建了WallpaperData,并没有其它和加载壁纸相关的操作。并且,这里创建的WallpaperData还未填充壁纸的有效信息。 
所以,接下来我们从另外一条线索开始分析。壁纸经常伴随着创建、移动、切换、删除等操作,那么肯定会有一个监听机制来监听壁纸的这一系列动作。于是,我们从WallpaperManagerService类的switchUser方法中找到了一个WallpaperObserver类。
public void onBootPhase(int phase) {
            if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
                mService.systemReady();
            } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
                mService.switchUser(UserHandle.USER_SYSTEM, null);
            }
        }
查看switchUser方法
void switchUser(int userId, IRemoteCallback reply) {
``````
        if(wallpaper.wallpaperObserver == null) {
            wallpaper.wallpaperObserver = new WallpaperManagerService.WallpaperObserver(wallpaper);
            wallpaper.wallpaperObserver.startWatching();
        }
``````
}
接着查看switchWallpaper()方法
void switchWallpaper(WallpaperManagerService.WallpaperData wallpaper, IRemoteCallback reply) {
``````
        try {
            ComponentName cname = wallpaper.wallpaperComponent != null?wallpaper.wallpaperComponent:wallpaper.nextWallpaperComponent;
            if(this.bindWallpaperComponentLocked(cname, true, false, wallpaper, reply)) {
                return;
            }
```````
}
分析下bindWallpaperComponentLocked
boolean bindWallpaperComponentLocked(ComponentName componentName, boolean force,
        boolean fromUser, WallpaperData wallpaper, IRemoteCallback reply) {
    // ...
    try {
         /* 当componentName为null时表示使用默认壁纸。
          这里会将componentName參数改为默认壁纸的componentName */
        if (componentName == null) {
             /* 首先会尝试从com.android.internal.R.string.default_wallpaper_component
              中获取默认壁纸的componentName,这个值的设置位于res/values/config.xml中。*/
            // 这里获取的componentName=null
            componentName = WallpaperManager.getDefaultWallpaperComponent(mContext);
            if (componentName == null) {
                // 使用静态壁纸
                // Fall back to static image wallpaper
                componentName = mImageWallpaper;
                if (DEBUG) Slog.v(TAG, "Using image wallpaper");
            }
        }
        // ...
        // 对ComponentName所描写叙述的Service进行一系列的验证,以确保它是一个壁纸服务。
        // WallpaperConnection实现了ServiceConnection接口用于监听和WallpaperService之间的连接状态。
        WallpaperConnection newConn = new WallpaperConnection(wi, wallpaper);
        intent.setComponent(componentName);
        // ...
        /* 启动指定的壁纸服务。当服务启动完毕后,剩下的启动流程会在WallpaperConnection.onServiceConnected()中继续 */
        if (!mContext.bindServiceAsUser(intent, newConn,
                Context.BIND_AUTO_CREATE | Context.BIND_SHOWING_UI
                        | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE,
                new UserHandle(serviceUserId))) {
            // ...
        }
         // 新的的壁纸服务启动成功后。便通过detachWallpaperLocked()销毁旧有的壁纸服务
        if (wallpaper.userId == mCurrentUserId && mLastWallpaper != null) {
                detachWallpaperLocked(mLastWallpaper);
        }
         // 将新的壁纸服务的执行信息保存到WallpaperData中
        wallpaper.wallpaperComponent = componentName;
        wallpaper.connection = newConn;       
        // 最后向WMS申请注冊一个WALLPAPER类型的窗体令牌。
        mIWindowManager.addWindowToken(newConn.mToken,
                WindowManager.LayoutParams.TYPE_WALLPAPER);
}
接着我们看下onServiceConnected()
public void onServiceConnected(ComponentName name, IBinder service) {
    synchronized (mLock) {
        if (mWallpaper.connection == this) {
            // ImageWallpaper的onBind方法返回值就是这个mService
            mService = IWallpaperService.Stub.asInterface(service);
            attachServiceLocked(this, mWallpaper);
            saveSettingsLocked(mWallpaper);
        }
    }
}
WallpaperConnection它不仅实现了ServiceConnection接口用于监听和WallpaperService之间的连接状态。在服务绑定成功后的WallpaperConnection.onServiceConnected()方法调用中,WallpaperConnection的实例会被发送给WallpaperService,使其作为WallpaperService向WallpaperManagerService进行通信的桥梁。
void attachServiceLocked(WallpaperConnection conn, WallpaperData wallpaper) {
    try {
        // 这里会调用IWallpaperServiceWrapper的attach方法,将创建壁纸窗体所需的信息发送给壁纸服务。
        conn.mService.attach(conn, conn.mToken,
                WindowManager.LayoutParams.TYPE_WALLPAPER, false,
                wallpaper.width, wallpaper.height, wallpaper.padding);
    } catch (RemoteException e) {
        // ...
        }
    }
}


public void attach(IWallpaperConnection conn, IBinder windowToken,
        int windowType, boolean isPreview, int reqWidth, int reqHeight, Rect padding) {
    // 使用WallpaperManagerService提供的參数构造一个IWallpaperEngineWarapper实例
    new IWallpaperEngineWrapper(mTarget, conn, windowToken,
            windowType, isPreview, reqWidth, reqHeight, padding);
}
IWallpaperEngineWrapper(WallpaperService context,
        IWallpaperConnection conn, IBinder windowToken,
        int windowType, boolean isPreview, int reqWidth, int reqHeight, Rect padding) {
    // 类成员变量初始化
    // ...
    Message msg = mCaller.obtainMessage(DO_ATTACH);
    mCaller.sendMessage(msg);
}
接下来分析DO_ATTACH消息的处理:
public void executeMessage(Message message) {
    switch (message.what) {
        case DO_ATTACH: {
            try {
                // 把IWallpaperEngineWrapper实例传递给WallpaperConnection进行保存。
                mConnection.attachEngine(this);
            } catch (RemoteException e) {
                Log.w(TAG, "Wallpaper host disappeared", e);
                return;
            }
            // 通过onCreateEngine()方法创建一个Engine。WallpaperService仅仅是提供壁纸执行的场所,而Engine才是真正的壁纸的实现
            Engine engine = onCreateEngine();
            mEngine = engine;
            mActiveEngines.add(engine);
            engine.attach(this);
            return;
        }
        // ...
    }
}


WallpaperService类中的onCreateEngine方法是一个抽象方法,ImageWallpaper类中实现了此方法。回想一下,在bindWallpaperComponentLocked方法中我们绑定的就是ImageWallpaper服务。
@Override
public Engine onCreateEngine() {
    // 创建了一个DrawableEngine实例
    mEngine = new DrawableEngine();
    return mEngine;
}


Engine创建完毕之后会通过Engine.attach()方法完毕Engine的初始化工作。
void attach(IWallpaperEngineWrapper wrapper) {
    // ...
    // ...
    // Engine的初始化工作
    onCreate(mSurfaceHolder);
    mInitializing = false;
    mReportedVisible = false;
    // 绘制壁纸
    updateSurface(false, false, false);
}


@Override
public void onCreate(SurfaceHolder surfaceHolder) {
    // ...
    updateSurfaceSize(surfaceHolder, getDefaultDisplayInfo());
}
void updateSurfaceSize(SurfaceHolder surfaceHolder, DisplayInfo displayInfo) {
    // ...
    // 将mWallpaper和mDefaultWallpaper重置为null
    WallpaperManager.forgetLoadedWallpaper();
    updateWallpaperLocked();
    ...
}
private void updateWallpaperLocked() {
    // ...
    mBackground = mWallpaperManager.getBitmap();
    // ...
}
//getBitmap()方法在framework/base/core/java/android/app/WallpaperManager.java里面
public Bitmap getBitmap() {
    return sGlobals.peekWallpaperBitmap(mContext, true);
}
public Bitmap peekWallpaperBitmap(Context context, boolean returnDefault) {
    synchronized (this) {
        // 如果已经加载了壁纸,则直接返回。
        if (mWallpaper != null) {
            return mWallpaper;
        }
        // 如果没有加载壁纸,则返回默认壁纸。
        if (mDefaultWallpaper != null) {
            return mDefaultWallpaper;
        }
        mWallpaper = null;
        try {
            // 首次开机,这里获取的wallpaper=null
            mWallpaper = getCurrentWallpaperLocked(context);
        } catch (OutOfMemoryError e) {
            Log.w(TAG, "No memory load current wallpaper", e);
        }
        if (returnDefault) {
            if (mWallpaper == null) {
                mDefaultWallpaper = getDefaultWallpaperLocked(context);
                return mDefaultWallpaper;
            } else {
                mDefaultWallpaper = null;
            }
        }
        return mWallpaper;
    }
}


private Bitmap getCurrentWallpaperLocked(Context context) {
    if (mService == null) {
        Log.w(TAG, "WallpaperService not running");
        return null;
    }
    try {
        Bundle params = new Bundle();
        // 获取/data/system/users/0/wallpaper的文件描述符
        ParcelFileDescriptor fd = mService.getWallpaper(this, params);
        if (fd != null) {
            try {
                BitmapFactory.Options options = new BitmapFactory.Options();
                return BitmapFactory.decodeFileDescriptor(
                        fd.getFileDescriptor(), null, options);
            } catch (OutOfMemoryError e) {
                Log.w(TAG, "Can't decode file", e);
            } finally {
                try {
                    fd.close();
                } catch (IOException e) {
                    // Ignore
                }
            }
        }
    } catch (RemoteException e) {
        // Ignore
    }
    return null;
}


public ParcelFileDescriptor getWallpaper(IWallpaperManagerCallback cb,
        Bundle outParams) {
    synchronized (mLock) {
        // ...
        // 从mWallpaperMap中获取对应用户的WallpapaerData
        WallpaperData wallpaper = mWallpaperMap.get(wallpaperUserId);
        if (wallpaper == null) {
            return null;
        }
        // 从WallpaperData中获取壁纸的尺寸信息并保存在outParms中
        try {
            if (outParams != null) {
                outParams.putInt("width", wallpaper.width);
                outParams.putInt("height", wallpaper.height);
            }
            wallpaper.callbacks.register(cb);
            File f = new File(getWallpaperDir(wallpaperUserId), WALLPAPER);
            if (!f.exists()) {
                return null;
            }
            // 将文件包装为一个文件描述符并返回给调用者
            return ParcelFileDescriptor.open(f, MODE_READ_ONLY);
        } catch (FileNotFoundException e) {
            /* Shouldn't happen as we check to see if the file exists */
            Slog.w(TAG, "Error getting wallpaper", e);
        }
        return null;
    }
}


private Bitmap getDefaultWallpaperLocked(Context context) {
    InputStream is = openDefaultWallpaper(context);
    // ...
}
public static InputStream openDefaultWallpaper(Context context) {
    // 配置wallpaper路径
    // ... 
    return context.getResources().openRawResource(
            com.android.internal.R.drawable.default_wallpaper);
}


WallpaperService$Engine->updateSurface():
Engine的updateSurface()方法将会创建壁纸窗体及Surface,并进行壁纸的绘制。


回去看下WallpaperObserver类,监听了壁纸变化,是一个非常重要的类
public WallpaperObserver(WallpaperData wallpaper) {
            //监听/data/system/users/0/下CLOSE_WRITE | MOVED_TO | DELETE | DELETE_SELF几个事件
            super(getWallpaperDir(wallpaper.userId).getAbsolutePath(),
                    CLOSE_WRITE | MOVED_TO | DELETE | DELETE_SELF);
            ``````
}
接着看响应方法
public void onEvent(int event, String path) {
        ``````
        synchronized (mLock) {
            // ...
            // 绑定壁纸组件
            File changedFile = new File(mWallpaperDir, path);
            if (mWallpaperFile.equals(changedFile)) {
                bindWallpaperComponentLocked(mImageWallpaper, true,
                                false, mWallpaper, null);
                // 保存壁纸信息,和loadSettingsLocked相反。
                saveSettingsLocked(mWallpaper);
            }       
    }
}