Aosp14系统壁纸的启动和加载流程
技术文章大纲:AOSP 14 系统壁纸加载流程
背景与概述
- 系统壁纸在Android用户体验中的重要性
- AOSP 14 壁纸模块的架构定位
- 核心组件:WallpaperManagerService、ImageWallpaper、LiveWallpaper
壁纸类型与数据源
- 静态壁纸(Bitmap/Drawable资源)
- 动态壁纸(LiveWallpaper)的实现差异
- 默认壁纸资源路径:
frameworks/base/core/res/res/drawable-nodpi/
核心加载流程
- 初始化阶段
WallpaperManagerService
在SystemServer中的启动调用了
这里先看一下打印的日志
10-15 18:36:56.494 589 589 I denghl : bindWallpaperComponentLocked
10-15 18:36:56.494 589 589 I denghl : java.lang.Exception
10-15 18:36:56.494 589 589 I denghl : at com.android.server.wallpaper.WallpaperManagerService.bindWallpaperComponentLocked(WallpaperManagerService.java:3182)
10-15 18:36:56.494 589 589 I denghl : at com.android.server.wallpaper.WallpaperManagerService.switchWallpaper(WallpaperManagerService.java:1805)
10-15 18:36:56.494 589 589 I denghl : at com.android.server.wallpaper.WallpaperManagerService.switchUser(WallpaperManagerService.java:1781)
10-15 18:36:56.494 589 589 I denghl : at com.android.server.wallpaper.WallpaperManagerService.onBootPhase(WallpaperManagerService.java:1674)
10-15 18:36:56.494 589 589 I denghl : at com.android.server.wallpaper.WallpaperManagerService$Lifecycle.onBootPhase(WallpaperManagerService.java:178)
10-15 18:36:56.494 589 589 I denghl : at com.android.server.SystemServiceManager.startBootPhase(SystemServiceManager.java:291)
10-15 18:36:56.494 589 589 I denghl : at com.android.server.SystemServer.lambda$startOtherServices$6(SystemServer.java:3140)
10-15 18:36:56.494 589 589 I denghl : at com.android.server.SystemServer.$r8$lambda$R8_YVQM1rsXoSgswlNNq9SsFhyw(SystemServer.java:0)
10-15 18:36:56.494 589 589 I denghl : at com.android.server.SystemServer$$ExternalSyntheticLambda6.run(R8$$SyntheticClass:0)
10-15 18:36:56.494 589 589 I denghl : at com.android.server.am.ActivityManagerService.systemReady(ActivityManagerService.java:8825)
10-15 18:36:56.494 589 589 I denghl : at com.android.server.SystemServer.startOtherServices(SystemServer.java:2992)
10-15 18:36:56.494 589 589 I denghl : at com.android.server.SystemServer.run(SystemServer.java:965)
10-15 18:36:56.494 589 589 I denghl : at com.android.server.SystemServer.main(SystemServer.java:686)
10-15 18:36:56.494 589 589 I denghl : at java.lang.reflect.Method.invoke(Native Method)
10-15 18:36:56.494 589 589 I denghl : at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:552)
10-15 18:36:56.494 589 589 I denghl : at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:856)
10-15 18:36:56.501 589 589 I denghl : bindWallpaperComponentLocked
10-15 18:36:56.501 589 589 I denghl : java.lang.Exception
10-15 18:36:56.501 589 589 I denghl : at com.android.server.wallpaper.WallpaperManagerService.bindWallpaperComponentLocked(WallpaperManagerService.java:3182)
10-15 18:36:56.501 589 589 I denghl : at com.android.server.wallpaper.WallpaperManagerService.switchWallpaper(WallpaperManagerService.java:1805)
10-15 18:36:56.501 589 589 I denghl : at com.android.server.wallpaper.WallpaperManagerService.switchUser(WallpaperManagerService.java:1783)
10-15 18:36:56.501 589 589 I denghl : at com.android.server.wallpaper.WallpaperManagerService.onBootPhase(WallpaperManagerService.java:1674)
10-15 18:36:56.501 589 589 I denghl : at com.android.server.wallpaper.WallpaperManagerService$Lifecycle.onBootPhase(WallpaperManagerService.java:178)
10-15 18:36:56.501 589 589 I denghl : at com.android.server.SystemServiceManager.startBootPhase(SystemServiceManager.java:291)
10-15 18:36:56.501 589 589 I denghl : at com.android.server.SystemServer.lambda$startOtherServices$6(SystemServer.java:3140)
10-15 18:36:56.501 589 589 I denghl : at com.android.server.SystemServer.$r8$lambda$R8_YVQM1rsXoSgswlNNq9SsFhyw(SystemServer.java:0)
10-15 18:36:56.501 589 589 I denghl : at com.android.server.SystemServer$$ExternalSyntheticLambda6.run(R8$$SyntheticClass:0)
10-15 18:36:56.501 589 589 I denghl : at com.android.server.am.ActivityManagerService.systemReady(ActivityManagerService.java:8825)
10-15 18:36:56.501 589 589 I denghl : at com.android.server.SystemServer.startOtherServices(SystemServer.java:2992)
10-15 18:36:56.501 589 589 I denghl : at com.android.server.SystemServer.run(SystemServer.java:965)
10-15 18:36:56.501 589 589 I denghl : at com.android.server.SystemServer.main(SystemServer.java:686)
10-15 18:36:56.501 589 589 I denghl : at java.lang.reflect.Method.invoke(Native Method)
10-15 18:36:56.501 589 589 I denghl : at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:552)
10-15 18:36:56.501 589 589 I denghl : at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:856)
根据日志分析在服务启动时候调用到了WallpaperManagerService(后面简称WPMS)的onBootPhase
@Overridepublic void onBootPhase(int phase) {// If someone set too large jpg file as wallpaper, system_server may be killed by lmk in// generateCrop(), so we create a file in generateCrop() before ImageDecoder starts working// and delete this file after ImageDecoder finishing. If the specific file exists, that// means ImageDecoder can't handle the original wallpaper file, in order to avoid// system_server restart again and again and rescue party will trigger factory reset,// so we reset default wallpaper in case system_server is trapped into a restart loop.errorCheck(UserHandle.USER_SYSTEM);if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {systemReady();} else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {switchUser(UserHandle.USER_SYSTEM, null);}}
这里调用了switchUser(),看看这个代码
void switchUser(int userId, IRemoteCallback reply) {TimingsTraceAndSlog t = new TimingsTraceAndSlog(TAG);t.traceBegin("Wallpaper_switch-user-" + userId);try {final WallpaperData systemWallpaper;final WallpaperData lockWallpaper;synchronized (mLock) {......if (systemWallpaper.wallpaperObserver == null) {systemWallpaper.wallpaperObserver = new WallpaperObserver(systemWallpaper);systemWallpaper.wallpaperObserver.startWatching();}if (lockWallpaper != systemWallpaper) {switchWallpaper(lockWallpaper, null);}switchWallpaper(systemWallpaper, reply);}......} finally {t.traceEnd();}}
从这里可以看出来调用了2次SwitchWallPaper,这也是为什么在Aosp14中有设置了锁屏后有2个ImageWallpaper,通过adb shell dumpsys activity containers
└─ Leaf:0:1 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]├─ WallpaperWindowToken{64b5447 token=android.os.Binder@c0d5c61} type=undefined mode=fullscreen override-mode=fullscreen requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]│ └─ e1e0b4c com.android.systemui.wallpapers.ImageWallpaper type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]└─ WallpaperWindowToken{bae55ba token=android.os.Binder@d5585dc} type=undefined mode=fullscreen override-mode=fullscreen requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]└─ 8966a36 com.android.systemui.wallpapers.ImageWallpaper type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
继续查看switchWallpaper,这里主要调用了bindWallpaperComponentLocked()
void switchWallpaper(WallpaperData wallpaper, IRemoteCallback reply) {synchronized (mLock) {if ((wallpaper.mWhich & FLAG_SYSTEM) != 0) mHomeWallpaperWaitingForUnlock = false;if ((wallpaper.mWhich & FLAG_LOCK) != 0) mLockWallpaperWaitingForUnlock = false;final ComponentName cname = wallpaper.wallpaperComponent != null ?wallpaper.wallpaperComponent : wallpaper.nextWallpaperComponent;if (!bindWallpaperComponentLocked(cname, true, false, wallpaper, reply)) {// We failed to bind the desired wallpaper, but that might// happen if the wallpaper isn't direct-boot awareServiceInfo si = null;try {si = mIPackageManager.getServiceInfo(cname,PackageManager.MATCH_DIRECT_BOOT_UNAWARE, wallpaper.userId);} catch (RemoteException e) {Slog.w(TAG, "Failure starting previous wallpaper; clearing", e);}onSwitchWallpaperFailLocked(wallpaper, reply, si);}}}
这里看看这个
boolean bindWallpaperComponentLocked(ComponentName componentName, boolean force,boolean fromUser, WallpaperData wallpaper, IRemoteCallback reply) {......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, clientIntent);int bindFlags = Context.BIND_AUTO_CREATE | Context.BIND_SHOWING_UI| Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE| Context.BIND_INCLUDE_CAPABILITIES;if (mContext.getResources().getBoolean(com.android.internal.R.bool.config_wallpaperTopApp)) {bindFlags |= Context.BIND_SCHEDULE_LIKE_TOP_APP;}android.util.Log.i("denghl","bindWallpaperComponentLocked",new Exception());Handler handler = Flags.bindWallpaperServiceOnItsOwnThreadDuringAUserSwitch()&& !mIsInitialBinding.compareAndSet(true, false)? mHandlerThread.getThreadHandler() : mContext.getMainThreadHandler();boolean bindSuccess = mContext.bindServiceAsUser(intent, newConn, bindFlags, handler,new UserHandle(serviceUserId));......
}
这里运用了binder跨进程通信,和SystemUI的WallpaperService进行了双向绑定,这里先看看这个WallpaperConnection(),在bingservice成功后,会执行OnServiceConnected(),最后调用到connectLocked(),
mWindowManagerInternal.addWindowToken(mToken, TYPE_WALLPAPER, mDisplayId,
挂载了TYPE_WALLPAPER到层级结构树中,再调用connection.mService.attach,这里是跨进程调用WallPaparService中的attach
public void onServiceConnected(ComponentName name, IBinder service) {TimingsTraceAndSlog t = new TimingsTraceAndSlog(TAG);t.traceBegin("WPMS.onServiceConnected-" + name);synchronized (mLock) {if (mWallpaper.connection == this) {mService = IWallpaperService.Stub.asInterface(service);attachServiceLocked(this, mWallpaper);......}t.traceEnd();}private void attachServiceLocked(WallpaperConnection conn, WallpaperData wallpaper) {TimingsTraceAndSlog t = new TimingsTraceAndSlog(TAG);t.traceBegin("WPMS.attachServiceLocked");conn.forEachDisplayConnector(connector-> connector.connectLocked(conn, wallpaper));t.traceEnd();}void connectLocked(WallpaperConnection connection, WallpaperData wallpaper) {//在这里挂在了token到层级结构树中mWindowManagerInternal.addWindowToken(mToken, TYPE_WALLPAPER, mDisplayId,null /* options */);mWindowManagerInternal.setWallpaperShowWhenLocked(mToken, (wallpaper.mWhich & FLAG_LOCK) != 0);final DisplayData wpdData =mWallpaperDisplayHelper.getDisplayDataOrCreate(mDisplayId);try {connection.mService.attach(connection, mToken, TYPE_WALLPAPER, false,wpdData.mWidth, wpdData.mHeight,wpdData.mPadding, mDisplayId, wallpaper.mWhich, connection.mInfo);} catch (RemoteException e) {Slog.w(TAG, "Failed attaching wallpaper on display", e);if (wallpaper != null && !wallpaper.wallpaperUpdating&& connection.getConnectedEngineSize() == 0) {bindWallpaperComponentLocked(null /* componentName */, false /* force */,false /* fromUser */, wallpaper, null /* reply */);}}t.traceEnd();}
查看WallpaperService代码,找到对应的方法
class IWallpaperServiceWrapper extends IWallpaperService.Stub {@Overridepublic void attach(IWallpaperConnection conn, IBinder windowToken,int windowType, boolean isPreview, int reqWidth, int reqHeight, Rect padding,int displayId, @SetWallpaperFlags int which, @Nullable WallpaperInfo info) {Trace.beginSection("WPMS.ServiceWrapper.attach");IWallpaperEngineWrapper engineWrapper =new IWallpaperEngineWrapper(mTarget, conn, windowToken, windowType,isPreview, reqWidth, reqHeight, padding, displayId, which, info);synchronized (mActiveEngines) {mActiveEngines.put(windowToken, engineWrapper);}if (DEBUG) {Slog.v(TAG, "IWallpaperServiceWrapper Attaching window token " + windowToken);}Trace.endSection();}}
这里主要是初始化了IWallpaperEngineWrapper(),在初始化中通过handler.sendMessage(DO_ATTACH),这里我过滤掉不关心的代码。只看我们关心的代码
class IWallpaperEngineWrapper extends IWallpaperEngine.Stubimplements HandlerCaller.Callback {private final HandlerCaller mCaller;final IWallpaperConnection mConnection;final IBinder mWindowToken;Engine mEngine;@SetWallpaperFlags int mWhich;IWallpaperEngineWrapper(WallpaperService service,IWallpaperConnection conn, IBinder windowToken,int windowType, boolean isPreview, int reqWidth, int reqHeight, Rect padding,int displayId, @SetWallpaperFlags int which, @Nullable WallpaperInfo info) {mWallpaperManager = getSystemService(WallpaperManager.class);......mCaller = new HandlerCaller(service, service.onProvideEngineLooper(), this, true);Message msg = mCaller.obtainMessage(DO_ATTACH);mCaller.sendMessage(msg);}@Overridepublic void executeMessage(Message message) {switch (message.what) {case DO_ATTACH: {Trace.beginSection("WPMS.DO_ATTACH");doAttachEngine();Trace.endSection();return;}......}}private void doAttachEngine() {Trace.beginSection("WPMS.onCreateEngine");Engine engine = onCreateEngine();Trace.endSection();mEngine = engine;Trace.beginSection("WPMS.mConnection.attachEngine-" + mDisplayId);try {mConnection.attachEngine(this, mDisplayId);} catch (RemoteException e) {engine.detach();Log.w(TAG, "Wallpaper host disappeared", e);return;} catch (IllegalStateException e) {Log.w(TAG, "Connector instance already destroyed, "+ "can't attach engine to non existing connector", e);return;} finally {Trace.endSection();}Trace.beginSection("WPMS.engine.attach");engine.attach(this);Trace.endSection();}}
最后通过engine.attach(this)调用到了Engine中,在这里主要调用到了updateSurface(),这里就是最后加载和显示的地方了
void attach(IWallpaperEngineWrapper wrapper) {.....updateSurface(false, false, false);}
在这里调用Session的
mSession.addToDisplay
mSession.relayout
void updateSurface(boolean forceRelayout, boolean forceReport, boolean redrawNeeded) {if (forceRelayout || creating || surfaceCreating || formatChanged || sizeChanged|| typeChanged || flagsChanged || redrawNeeded|| !mIWallpaperEngine.mShownReported) {if (!mCreated) {// Add windowmLayout.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();if (mSession.addToDisplay(mWindow, mLayout, View.VISIBLE,mDisplay.getDisplayId(), WindowInsets.Type.defaultVisible(),inputChannel, mInsetsState, mTempControls, new Rect(),new float[1]) < 0) {return;}mCreated = true;}mSurfaceHolder.mSurfaceLock.lock();mDrawingAllowed = true;final int relayoutResult = mSession.relayout(mWindow, mLayout, mWidth, mHeight,View.VISIBLE, 0, 0, 0, mWinFrames, mMergedConfiguration,mSurfaceControl, mInsetsState, mTempControls, mSyncSeqIdBundle);try {mSurfaceHolder.ungetCallbacks();redrawNeeded |= creating || (relayoutResult& WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0;if (forceReport || creating || surfaceCreating|| formatChanged || sizeChanged) {if (DEBUG) {RuntimeException e = new RuntimeException();e.fillInStackTrace();Log.w(TAG, "forceReport=" + forceReport + " creating=" + creating+ " formatChanged=" + formatChanged+ " sizeChanged=" + sizeChanged, e);}if (DEBUG) Log.v(TAG, "onSurfaceChanged("+ mSurfaceHolder + ", " + mFormat+ ", " + mCurWidth + ", " + mCurHeight+ "): " + this);didSurface = true;Trace.beginSection("WPMS.Engine.onSurfaceChanged");onSurfaceChanged(mSurfaceHolder, mFormat,mCurWidth, mCurHeight);Trace.endSection();SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();if (callbacks != null) {for (SurfaceHolder.Callback c : callbacks) {c.surfaceChanged(mSurfaceHolder, mFormat,mCurWidth, mCurHeight);}}}} finally {mIsCreating = false;mSurfaceCreated = true;if (redrawNeeded) {mSession.finishDrawing(mWindow, null /* postDrawTransaction */,Integer.MAX_VALUE);processLocalColors();}reposition();reportEngineShown(shouldWaitForEngineShown());}} catch (RemoteException ex) {}if (DEBUG) Log.v(TAG, "Layout: x=" + mLayout.x + " y=" + mLayout.y +" w=" + mLayout.width + " h=" + mLayout.height);}}
到这里基本就到了wms相关内容了。绘制一个简单的流程图