frameworks 之 WallpaperManagerService 壁纸管理
frameworks 之 WallpaperManagerService
- 1. 启动服务
- 2. 初始化
- 2.1 构造方法
- 2.2 onBootPhase
- 3. 绑定对应的壁纸服务
- 3. 1 绑定成功回调
- 4. 壁纸的添加
- 5. 壁纸的移除
讲解壁纸启动流程以及添加窗口和移除窗口时机
涉及到的类如下
- frameworks/base/services/java/com/android/server/SystemServer.java
- frameworks/base/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
- frameworks/base/services/core/java/com/android/server/SystemServiceManager.java
- frameworks/base/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
- frameworks/base/core/java/android/service/wallpaper/WallpaperService.java
1. 启动服务
壁纸管理的启动来自 SystemServer
- 调用 startOtherServices 时候方法时候,会从资源中 获取判断 config_enableWallpaperService 的值 是否为true, 为ture才启动。
- 调用 SystemServiceManager 的 startService 方法,并将要启动的类(WALLPAPER_SERVICE_CLASS)传递进入。
private static final String WALLPAPER_SERVICE_CLASS =
"com.android.server.wallpaper.WallpaperManagerService$Lifecycle";
private void startOtherServices(@NonNull TimingsTraceAndSlog t) {
...
// 启动壁纸管理服务,判断是否要启动,默认为true
// WALLPAPER_SERVICE_CLASS: com.android.server.wallpaper.WallpaperManagerService$Lifecycle
if (context.getResources().getBoolean(R.bool.config_enableWallpaperService)) {
t.traceBegin("StartWallpaperManagerService");
mSystemServiceManager.startService(WALLPAPER_SERVICE_CLASS);
t.traceEnd();
} else {
Slog.i(TAG, "Wallpaper service disabled by config");
}
...
}
startService 方法会基于反射构造对应的类,并调用其构造方法 创建该类。
public SystemService startService(String className) {
final Class<SystemService> serviceClass = loadClassFromLoader(className,
this.getClass().getClassLoader());
return startService(serviceClass);
}
public <T extends SystemService> T startService(Class<T> serviceClass) {
try {
final String name = serviceClass.getName();
Slog.i(TAG, "Starting " + name);
Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "StartService " + name);
// Create the service.
if (!SystemService.class.isAssignableFrom(serviceClass)) {
throw new RuntimeException("Failed to create " + name
+ ": service must extend " + SystemService.class.getName());
}
final T service;
try {
Constructor<T> constructor = serviceClass.getConstructor(Context.class);
service = constructor.newInstance(mContext);
}
...
startService(service);
return service;
} finally {
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
}
}
在将该类放到 mServices 数组中,调用其 onStart 方法。
public void startService(@NonNull final SystemService service) {
// Register it.
mServices.add(service);
// Start it.
long time = SystemClock.elapsedRealtime();
try {
service.onStart();
} catch (RuntimeException ex) {
throw new RuntimeException("Failed to start service " + service.getClass().getName()
+ ": onStart threw an exception", ex);
}
warnIfTooLong(SystemClock.elapsedRealtime() - time, service, "onStart");
}
查看新构建的类 对应的 onStart 方法。
- 从 资源中 读取 config_wallpaperManagerServiceName 的值, 默认值为 com.android.server.wallpaper.WallpaperManagerService
- 调用类加载方法创建类 WallpaperManagerService,并调用其构造方法。
- 通过 publishBinderService 方法,将该服务添加到 ServiceManger 中。
这样壁纸管理服务就启动了。
public static class Lifecycle extends SystemService {
private IWallpaperManagerService mService;
public Lifecycle(Context context) {
super(context);
}
@Override
public void onStart() {
try {
// 从 SystemServiceManager 调用 startService调用
final Class<? extends IWallpaperManagerService> klass =
(Class<? extends IWallpaperManagerService>)Class.forName(
getContext().getResources().getString(
R.string.config_wallpaperManagerServiceName));
mService = klass.getConstructor(Context.class).newInstance(getContext());
publishBinderService(Context.WALLPAPER_SERVICE, mService);
} catch (Exception exp) {
Slog.wtf(TAG, "Failed to instantiate WallpaperManagerService", exp);
}
}
}
2. 初始化
2.1 构造方法
- 从资源文件获取 image_wallpaper_component 的值,默认为 com.android.systemui/com.android.systemui.ImageWallpaper。会根据该值去绑定对应的服务。并保存到 mImageWallpaper 属性。
- 从 WallpaperManager 的 getDefaultWallpaperComponent 方法获取默认的壁纸值。保存到 mDefaultWallpaperComponent 属性。该方法实际是从系统属性读取ro.config.wallpaper_component 读取
- 初始化各种管理服务的类
- 创建 LocalService,通过 addService 方法添加到 LocalServices 中。
public WallpaperManagerService(Context context) {
if (DEBUG) Slog.v(TAG, "WallpaperService startup");
mContext = context;
mShuttingDown = false;
// 从 string 获取对应的壁纸容器服务 默认为com.android.systemui/com.android.systemui.ImageWallpaper
mImageWallpaper = ComponentName.unflattenFromString(
context.getResources().getString(R.string.image_wallpaper_component));
// 从系统属性(ro.config.wallpaper_component)获取默认的 壁纸组件
mDefaultWallpaperComponent = WallpaperManager.getDefaultWallpaperComponent(context);
mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
mIPackageManager = AppGlobals.getPackageManager();
mAppOpsManager = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
mDisplayManager = mContext.getSystemService(DisplayManager.class);
mDisplayManager.registerDisplayListener(mDisplayListener, null /* handler */);
mActivityManager = mContext.getSystemService(ActivityManager.class);
mMonitor = new MyPackageMonitor();
mColorsChangedListeners = new SparseArray<>();
// 将对应的WallpaperManagerInternal实现类添加到 LocalServices中
LocalServices.addService(WallpaperManagerInternal.class, new LocalService());
}
2.2 onBootPhase
AMS 初始化好会触发 systemReady 方法。
mActivityManagerService.systemReady(() -> {
Slog.i(TAG, "Making services ready");
t.traceBegin("StartActivityManagerReadyPhase");
mSystemServiceManager.startBootPhase(t, SystemService.PHASE_ACTIVITY_MANAGER_READY);
t.traceEnd();
}
mSystemServiceManager 调用 startBootPhase 方法。会遍历对应 mServices 数组,并调用 onBootPhase
public void startBootPhase(@NonNull TimingsTraceAndSlog t, int phase) {
if (phase <= mCurrentPhase) {
throw new IllegalArgumentException("Next phase must be larger than previous");
}
mCurrentPhase = phase;
Slog.i(TAG, "Starting phase " + mCurrentPhase);
try {
t.traceBegin("OnBootPhase_" + phase);
// 初始化的服务都会放在 mServices 里,会调用的 onBootPhase
final int serviceLen = mServices.size();
for (int i = 0; i < serviceLen; i++) {
final SystemService service = mServices.get(i);
long time = SystemClock.elapsedRealtime();
t.traceBegin("OnBootPhase_" + phase + "_" + service.getClass().getName());
try {
service.onBootPhase(mCurrentPhase);
} catch (Exception ex) {
throw new RuntimeException("Failed to boot service "
+ service.getClass().getName()
+ ": onBootPhase threw an exception during phase "
+ mCurrentPhase, ex);
}
warnIfTooLong(SystemClock.elapsedRealtime() - time, service, "onBootPhase");
t.traceEnd();
}
} finally {
t.traceEnd();
}
if (phase == SystemService.PHASE_BOOT_COMPLETED) {
final long totalBootTime = SystemClock.uptimeMillis() - mRuntimeStartUptime;
t.logDuration("TotalBootTime", totalBootTime);
SystemServerInitThreadPool.shutdown();
}
}
所以会调用 WallpaperManagerService 的 onBootPhase 方法
public static class Lifecycle extends SystemService {
...
@Override
public void onBootPhase(int phase) {
if (mService != null) {
mService.onBootPhase(phase);
}
}
...
}
接下来调用对应 systemReady 方法
- 调用 initialize 进行初始化壁纸数据, initialize 方法主要做了,
1.1 对壁纸目录进行初始化
1.2 调用 loadSettingsLocked 对数据进行初始化
1.3 在一次调用 getWallpaperSafeLocked 获取系统当前用户的壁纸数据
void initialize() {
mMonitor.register(mContext, null, UserHandle.ALL, true);
//1. 获取系统当前用户的壁纸目录
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.
// 加载本地数据
loadSettingsLocked(UserHandle.USER_SYSTEM, false);
// 在一次调用getWallpaperSafeLocked方法获取系统当前用户的壁纸数据
getWallpaperSafeLocked(UserHandle.USER_SYSTEM, FLAG_SYSTEM);
}
loadSettingsLocked 方法
1.1.1 获取需要解析的文件,路径为 data/system/users/0/wallpaper_info.xml,默认为空
1.1.2 调用chooseForRead,规则是 正式文件存在就选出正式文件,并删除临时文件;如果正式文件不存在就将临时文件重名为正式文件
1.1.3 根据用户id 从 mWallpaperMap 获取对应的数据,如果不存在则创建,并调用 initializeFallbackWallpaper 进行绑定(里面会调用 bindWallpaperComponentLocked)。
1.1.4 解析对应的 wallpaper_info.xml 文件。
private void loadSettingsLocked(int userId, boolean keepDimensionHints) {
// 调用JournaledFile的chooseForRead方法获取接下来需要解析的文件,其实就是data/system/users/0/wallpaper_info.xml文件
JournaledFile journal = makeJournaledFile(userId);
FileInputStream stream = null;
// 作用 正式文件存在就选出正式文件,并删除临时文件;如果正式文件不存在就将临时文件重名为正式文件
File file = journal.chooseForRead();
// 获取当前用户的壁纸数据
WallpaperData wallpaper = mWallpaperMap.get(userId);
// 如果为空则创建
if (wallpaper == null) {
// Do this once per boot
migrateFromOld();
// 参数意义 文件路径, 文件名称, 裁减文件
wallpaper = new WallpaperData(userId, getWallpaperDir(userId),
WALLPAPER, WALLPAPER_CROP);
wallpaper.allowBackup = true;
mWallpaperMap.put(userId, wallpaper);
if (!wallpaper.cropExists()) {
if (wallpaper.sourceExists()) {
generateCrop(wallpaper);
} else {
Slog.i(TAG, "No static wallpaper imagery; defaults will be shown");
}
}
// 进行服务绑定
initializeFallbackWallpaper();
}
boolean success = false;
final DisplayData wpdData = getDisplayDataOrCreate(DEFAULT_DISPLAY);
try {
stream = new FileInputStream(file);
// 开始解析 wallpaper_info.xml
TypedXmlPullParser parser = Xml.resolvePullParser(stream);
...
}
- 注册对应的监听 用户移除广播, 关机广播,注册用户切换
void systemReady() {
if (DEBUG) Slog.v(TAG, "systemReady");
initialize();
//获取系统当前用户的壁纸数据
WallpaperData wallpaper = mWallpaperMap.get(UserHandle.USER_SYSTEM);
// If we think we're going to be using the system image wallpaper imagery, make
// sure we have something to render
if (mImageWallpaper.equals(wallpaper.nextWallpaperComponent)) {
// No crop file? Make sure we've finished the processing sequence if necessary
if (!wallpaper.cropExists()) {
if (DEBUG) {
Slog.i(TAG, "No crop; regenerating from source");
}
generateCrop(wallpaper);
}
// Still nothing? Fall back to default.
if (!wallpaper.cropExists()) {
if (DEBUG) {
Slog.i(TAG, "Unable to regenerate crop; resetting");
}
clearWallpaperLocked(false, FLAG_SYSTEM, UserHandle.USER_SYSTEM, null);
}
} else {
if (DEBUG) {
Slog.i(TAG, "Nondefault wallpaper component; gracefully ignoring");
}
}
// 注册广播接收者,监听用户移除事件
IntentFilter userFilter = new IntentFilter();
userFilter.addAction(Intent.ACTION_USER_REMOVED);
mContext.registerReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (Intent.ACTION_USER_REMOVED.equals(action)) {
onRemoveUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
UserHandle.USER_NULL));
}
}
}, userFilter);
//注册广播接收者,监听关机广播
final IntentFilter shutdownFilter = new IntentFilter(Intent.ACTION_SHUTDOWN);
mContext.registerReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (Intent.ACTION_SHUTDOWN.equals(intent.getAction())) {
if (DEBUG) {
Slog.i(TAG, "Shutting down");
}
synchronized (mLock) {
mShuttingDown = true;
}
}
}
}, shutdownFilter);
//为ActivityManagerService注册回调方法,监听用户切换事件
try {
ActivityManager.getService().registerUserSwitchObserver(
new UserSwitchObserver() {
@Override
public void onUserSwitching(int newUserId, IRemoteCallback reply) {
errorCheck(newUserId);
switchUser(newUserId, reply);
}
}, TAG);
} catch (RemoteException e) {
e.rethrowAsRuntimeException();
}
}
3. 绑定对应的壁纸服务
bindWallpaperComponentLocked 方法会绑定对应的壁纸服务
- 会优先判断 设置的 mDefaultWallpaperComponent,如果还没就直接获取对应的 mImageWallpaper
- 判断是否有 android.permission.BIND_WALLPAPER 权限
- 判断是否默认的systemUi壁纸,不是的话需要判断该服务是否壁纸服务,通过遍历所有的壁纸服务,然后判断是否与要用的服务有想等的存在。
- 判断是否有 android.Manifest.permission.AMBIENT_WALLPAPER 权限
- 创建对应的 WallpaperConnection的绑定监听,对应的也是AIDL IWallpaperConnection 的实现类。
- 调用 bindServiceAsUser 进行绑定
- 判断是否一致,调用 detachWallpaperLocked 移除上一次的壁纸。
boolean bindWallpaperComponentLocked(ComponentName componentName, boolean force,
boolean fromUser, WallpaperData wallpaper, IRemoteCallback reply) {
if (DEBUG_LIVE) {
Slog.v(TAG, "bindWallpaperComponentLocked: componentName=" + componentName);
}
// Has the component changed?
if (!force && changingToSame(componentName, wallpaper)) {
return true;
}
try {
// 会优先 设置的 mDefaultWallpaperComponent,如果还没就直接获取对应的 mImageWallpaper
if (componentName == null) {
componentName = mDefaultWallpaperComponent;
if (componentName == null) {
// Fall back to static image wallpaper
componentName = mImageWallpaper;
//clearWallpaperComponentLocked();
//return;
if (DEBUG_LIVE) Slog.v(TAG, "No default component; using image wallpaper");
}
}
int serviceUserId = wallpaper.userId;
// 判断该壁纸服务是否存在
ServiceInfo si = mIPackageManager.getServiceInfo(componentName,
PackageManager.GET_META_DATA | PackageManager.GET_PERMISSIONS, serviceUserId);
if (si == null) {
// The wallpaper component we're trying to use doesn't exist
Slog.w(TAG, "Attempted wallpaper " + componentName + " is unavailable");
return false;
}
if (!android.Manifest.permission.BIND_WALLPAPER.equals(si.permission)) {
String msg = "Selected service does not have "
+ android.Manifest.permission.BIND_WALLPAPER
+ ": " + componentName;
if (fromUser) {
throw new SecurityException(msg);
}
Slog.w(TAG, msg);
return false;
}
WallpaperInfo wi = null;
Intent intent = new Intent(WallpaperService.SERVICE_INTERFACE);
// 判断是否默认的systemUi壁纸,不是的话需要判断该服务是否壁纸服务
if (componentName != null && !componentName.equals(mImageWallpaper)) {
// Make sure the selected service is actually a wallpaper service.
List<ResolveInfo> ris =
mIPackageManager.queryIntentServices(intent,
intent.resolveTypeIfNeeded(mContext.getContentResolver()),
PackageManager.GET_META_DATA, serviceUserId).getList();
for (int i=0; i<ris.size(); i++) {
ServiceInfo rsi = ris.get(i).serviceInfo;
if (rsi.name.equals(si.name) &&
rsi.packageName.equals(si.packageName)) {
try {
wi = new WallpaperInfo(mContext, ris.get(i));
} catch (XmlPullParserException e) {
if (fromUser) {
throw new IllegalArgumentException(e);
}
Slog.w(TAG, e);
return false;
} catch (IOException e) {
if (fromUser) {
throw new IllegalArgumentException(e);
}
Slog.w(TAG, e);
return false;
}
break;
}
}
if (wi == null) {
String msg = "Selected service is not a wallpaper: "
+ componentName;
if (fromUser) {
throw new SecurityException(msg);
}
Slog.w(TAG, msg);
return false;
}
}
// 再次判断权限
if (wi != null && wi.supportsAmbientMode()) {
final int hasPrivilege = mIPackageManager.checkPermission(
android.Manifest.permission.AMBIENT_WALLPAPER, wi.getPackageName(),
serviceUserId);
if (hasPrivilege != PackageManager.PERMISSION_GRANTED) {
String msg = "Selected service does not have "
+ android.Manifest.permission.AMBIENT_WALLPAPER
+ ": " + componentName;
if (fromUser) {
throw new SecurityException(msg);
}
Slog.w(TAG, msg);
return false;
}
}
// Bind the service!
if (DEBUG) Slog.v(TAG, "Binding to:" + componentName);
final int componentUid = mIPackageManager.getPackageUid(componentName.getPackageName(),
MATCH_DIRECT_BOOT_AUTO, wallpaper.userId);
// 是 IWallpaperConnection.Stub 的实现类 服务端 继承ServiceConnection绑定监听
WallpaperConnection newConn = new WallpaperConnection(wi, wallpaper, componentUid);
intent.setComponent(componentName);
intent.putExtra(Intent.EXTRA_CLIENT_LABEL,
com.android.internal.R.string.wallpaper_binding_label);
intent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivityAsUser(
mContext, 0,
Intent.createChooser(new Intent(Intent.ACTION_SET_WALLPAPER),
mContext.getText(com.android.internal.R.string.chooser_wallpaper)),
PendingIntent.FLAG_IMMUTABLE, null, new UserHandle(serviceUserId)));
if (!mContext.bindServiceAsUser(intent, newConn,
Context.BIND_AUTO_CREATE | Context.BIND_SHOWING_UI
| Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE
| Context.BIND_INCLUDE_CAPABILITIES,
new UserHandle(serviceUserId))) {
String msg = "Unable to bind service: "
+ componentName;
if (fromUser) {
throw new IllegalArgumentException(msg);
}
Slog.w(TAG, msg);
return false;
}
// 如果想等并且上一个壁纸不为空,则销毁上一个壁纸
if (wallpaper.userId == mCurrentUserId && mLastWallpaper != null
&& !wallpaper.equals(mFallbackWallpaper)) {
detachWallpaperLocked(mLastWallpaper);
}
wallpaper.wallpaperComponent = componentName;
wallpaper.connection = newConn;
newConn.mReply = reply;
if (wallpaper.userId == mCurrentUserId && !wallpaper.equals(mFallbackWallpaper)) {
mLastWallpaper = wallpaper;
}
updateFallbackConnection();
} catch (RemoteException e) {
String msg = "Remote exception for " + componentName + "\n" + e;
if (fromUser) {
throw new IllegalArgumentException(msg);
}
Slog.w(TAG, msg);
return false;
}
return true;
}
3. 1 绑定成功回调
回调绑定成功后,会调用 onServiceConnected
- 将对应的AIDL的 IWallpaperService 保存到 mService 变量。
- 调用 attachServiceLocked 对所有屏幕 进行attach操作
- 调用 saveSettingsLocked 方法,将对应的保存到 wallpaper_info.xml 文件
public void onServiceConnected(ComponentName name, IBinder service) {
synchronized (mLock) {
if (mWallpaper.connection == this) {
// 绑定成功,这是对应的 WallpaperService 服务类 AIDL
mService = IWallpaperService.Stub.asInterface(service);
// 遍历所有屏幕,进行attach操作
attachServiceLocked(this, mWallpaper);
// XXX should probably do saveSettingsLocked() later
// when we have an engine, but I'm not sure about
// locking there and anyway we always need to be able to
// recover if there is something wrong.
if (!mWallpaper.equals(mFallbackWallpaper)) {
saveSettingsLocked(mWallpaper.userId);
}
FgThread.getHandler().removeCallbacks(mResetRunnable);
// 绑定成功移除对应重绑任务
mContext.getMainThreadHandler().removeCallbacks(mTryToRebindRunnable);
}
}
}
4. 壁纸的添加
绑定服务成功后,会调用 attachServiceLocked 方法,该方法遍历后又会调用 connectLocked 方法
- 直接调用 WMS的 addWindowToken 方法,添加对应的token到层级树中。也是在token的构造方法添加。
- 调用 服务端的 attach 方法。该方法主要将 mToken 和 当前的 connection 也即是 IWallpaperConnection AIDL 实现方法,传递给绑定的壁纸服务,方便调用。
void connectLocked(WallpaperConnection connection, WallpaperData wallpaper) {
if (connection.mService == null) {
Slog.w(TAG, "WallpaperService is not connected yet");
return;
}
if (DEBUG) Slog.v(TAG, "Adding window token: " + mToken);
// 直接调用 WMS的 addWindowToken 方法构造新的token添加到层级树
mWindowManagerInternal.addWindowToken(mToken, TYPE_WALLPAPER, mDisplayId,
null /* options */);
final DisplayData wpdData = getDisplayDataOrCreate(mDisplayId);
try {
connection.mService.attach(connection, mToken, TYPE_WALLPAPER, false,
wpdData.mWidth, wpdData.mHeight,
wpdData.mPadding, mDisplayId);
}
}
查看attach 是实现方法,因为默认绑定的为 ImageWallpaper 服务,该服务继承 WallpaperService。所以 attach 要在 WallpaperService类查看。
IWallpaperServiceWrapper 是对应的 AILD实现。
该方法构造了 IWallpaperEngineWrapper 对象 并接收传过来的对应参数。
@Override
public void attach(IWallpaperConnection conn, IBinder windowToken,
int windowType, boolean isPreview, int reqWidth, int reqHeight, Rect padding,
int displayId) {
// 创建了对应的IWallpaperEngineWrapper windowToken是从WallpaperManagerService给到的
// 到时候会根据ibinder 从WMS的tokenMap拿出 windowToken
mEngineWrapper = new IWallpaperEngineWrapper(mTarget, conn, windowToken,
windowType, isPreview, reqWidth, reqHeight, padding, displayId);
}
构造方法里
- 将传过来的 壁纸管理AIDL对象保存到 mConnection, 将token 保存到 mWindowToken,并将其他参数都保存到成员变量
- 发送 DO_ATTACH 消息进行壁纸加载
IWallpaperEngineWrapper(WallpaperService context,
IWallpaperConnection conn, IBinder windowToken,
int windowType, boolean isPreview, int reqWidth, int reqHeight, Rect padding,
int displayId) {
mWallpaperManager = getSystemService(WallpaperManager.class);
mCaller = new HandlerCaller(context, context.getMainLooper(), this, true);
mConnection = conn;
mWindowToken = windowToken;
mWindowType = windowType;
...
if (mDisplay == null) {
// Ignore this engine.
throw new IllegalArgumentException("Cannot find display with id" + mDisplayId);
}
Message msg = mCaller.obtainMessage(DO_ATTACH);
mCaller.sendMessage(msg);
}
收到 DO_ATTACH 消息 主要做了
- 创建对应子类的 Engine,ImageWallpaper 创建的是 GLEngine
- 通过 mConnection 调用 attachEngine,执行 WallpaperManagerService 的方法将对应的渲染引起给对应的屏幕管理。
- 调用 attach 方法进行 窗口加载
case DO_ATTACH: {
// 拉起的是imageWallpaper 所以是GlEngine
Engine engine = onCreateEngine();
mEngine = engine;
try {
mConnection.attachEngine(this, mDisplayId);
} catch (RemoteException e) {
engine.detach();
Log.w(TAG, "Wallpaper host disappeared", e);
return;
}
mActiveEngines.add(engine);
// 执行attach方法进行壁纸展示
engine.attach(this);
return;
}
attach 方法
- 初始化参数,将传过来对应的参数放到对应的Engine 里
- 调用 updateSurface 开始加载窗口
void attach(IWallpaperEngineWrapper wrapper) {
...
mIWallpaperEngine = wrapper;
mCaller = wrapper.mCaller;
mConnection = wrapper.mConnection;
mWindowToken = wrapper.mWindowToken;
mSurfaceHolder.setSizeFromLayout();
mInitializing = true;
mSession = WindowManagerGlobal.getWindowSession();
mWindow.setSession(mSession);
...
updateSurface(false, false, false);
}
updateSurface 方法
- 填充对应 layoutParame 参数,并将token赋值给 token layoutParams的 token属性。
- 调用 mSession.addToDisplay,创建对应的windowState和之前文章的WMS一样。
- 创建 WallpaperInputEventReceiver 接收输入事件。
- 调用 mSession.relayout 创建对应的 surfaceControl 到 mSurfaceControl
- 判断 mSurfaceControl 是否可用,可用创建 BbqSurfaceControl 挂载到 mSurfaceControl 下
- 最后调用 mSession.finishDrawing 进行展示
void updateSurface(boolean forceRelayout, boolean forceReport, boolean redrawNeeded) {
...
// 填充对应layoutParame参数
try {
...
mLayout.flags = mWindowFlags
| WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
| WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR
| WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
mCurWindowPrivateFlags = mWindowPrivateFlags;
mLayout.privateFlags = mWindowPrivateFlags;
mLayout.memoryType = mType;
// 设置对应的token
mLayout.token = mWindowToken;
if (!mCreated) {
// Retrieve watch round info
TypedArray windowStyle = obtainStyledAttributes(
com.android.internal.R.styleable.Window);
windowStyle.recycle();
// Add window
mLayout.type = mIWallpaperEngine.mWindowType;
mLayout.gravity = Gravity.START|Gravity.TOP;
mLayout.setFitInsetsTypes(0 /* types */);
mLayout.setTitle(WallpaperService.this.getClass().getName());
mLayout.windowAnimations =
com.android.internal.R.style.Animation_Wallpaper;
InputChannel inputChannel = new InputChannel();
// 添加windowState到对应的界面,通过token查找
if (mSession.addToDisplay(mWindow, mLayout, View.VISIBLE,
mDisplay.getDisplayId(), mRequestedVisibilities, inputChannel,
mInsetsState, mTempControls) < 0) {
Log.w(TAG, "Failed to add window while updating wallpaper surface.");
return;
}
mSession.setShouldZoomOutWallpaper(mWindow, shouldZoomOutWallpaper());
mCreated = true;
// 设置输入
mInputEventReceiver = new WallpaperInputEventReceiver(
inputChannel, Looper.myLooper());
}
...
// 调用relayout 创建 surfaceControl 到 mSurfaceControl
final int relayoutResult = mSession.relayout(
mWindow, mLayout, mWidth, mHeight,
View.VISIBLE, 0, -1, mWinFrames, mMergedConfiguration, mSurfaceControl,
mInsetsState, mTempControls, mSurfaceSize);
if (mSurfaceControl.isValid()) {
// 添加 BbqSurfaceControl 到 mSurfaceControl 下
if (mBbqSurfaceControl == null) {
mBbqSurfaceControl = new SurfaceControl.Builder()
.setName("Wallpaper BBQ wrapper")
.setHidden(false)
// TODO(b/192291754)
.setMetadata(METADATA_WINDOW_TYPE, TYPE_WALLPAPER)
.setBLASTLayer() // 设置不是容器
.setParent(mSurfaceControl)
.setCallsite("Wallpaper#relayout")
.build();
updateSurfaceDimming();
}
...
try {
} finally {
mIsCreating = false;
mSurfaceCreated = true;
if (redrawNeeded) {
resetWindowPages();
// 最后进行展示
mSession.finishDrawing(mWindow, null /* postDrawTransaction */);
processLocalColors(mPendingXOffset, mPendingXOffsetStep);
}
reposition();
reportEngineShown(shouldWaitForEngineShown());
}
}
}
}
5. 壁纸的移除
移除是在WallpaperManagerService 绑定壁纸服务的成功时候,会调用 detachWallpaperLocked 方法
- 移除对应 壁纸服务的 detach 方法,该方法会移除对应的windowState 已经释放对应的 SurfaceContacl
- 遍历并调用对应的 disconnectLocked 方法,该方法会调用 mWindowManagerInternal。removeWindowToken 移除对应的token,并调用引擎的 destroy 方法。
private void detachWallpaperLocked(WallpaperData wallpaper) {
if (wallpaper.connection != null) {
...
try {
// It can be null if user switching happens before service connection.
// 移除对应的壁纸
if (wallpaper.connection.mService != null) {
wallpaper.connection.mService.detach();
}
} catch (RemoteException e) {
Slog.w(TAG, "Failed detaching wallpaper service ", e);
}
mContext.unbindService(wallpaper.connection);
wallpaper.connection.forEachDisplayConnector(
WallpaperConnection.DisplayConnector::disconnectLocked);
...
}
}
void disconnectLocked() {
if (DEBUG) Slog.v(TAG, "Removing window token: " + mToken);
mWindowManagerInternal.removeWindowToken(mToken, false/* removeWindows */,
mDisplayId);
try {
if (mEngine != null) {
mEngine.destroy();
}
} catch (RemoteException e) {
}
mEngine = null;
}