开机设置默认壁纸流程
在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);
}
}
}