Android 14 transtion 动画流程

embedded/2024/12/22 19:39:40/

1.接口

shell入口通过TransitionPlayerImpl与wm core 通信

java">@BinderThreadprivate class TransitionPlayerImpl extends ITransitionPlayer.Stub {@Overridepublic void onTransitionReady(IBinder iBinder, TransitionInfo transitionInfo,SurfaceControl.Transaction t, SurfaceControl.Transaction finishT)throws RemoteException {mMainExecutor.execute(() -> Transitions.this.onTransitionReady(iBinder, transitionInfo, t, finishT));}@Overridepublic void requestStartTransition(IBinder iBinder,TransitionRequestInfo request) throws RemoteException {mMainExecutor.execute(() -> Transitions.this.requestStartTransition(iBinder, request));}}
}
java">分为1. requestStartTransition2.onTransitionReady两个阶段1.requestStartTransition
wm servicesnew 一个动画放进mActiveSyncs中04-23 18:43:25.195 2077 4588 D jinyanmeiainima: BLASTSyncEngine startSyncSet s.mSyncId:6
04-23 18:43:25.195 2077 4588 D jinyanmeiainima: BLASTSyncEngine startSyncSet s:com.android.server.wm.BLASTSyncEngine$SyncGroup@3ee8531
04-23 18:43:25.195 2077 4588 D jinyanmeiainima: BLASTSyncEngine startSyncSet mActiveSyncs++++:0
04-23 18:43:25.196 2077 4588 D jinyanmeiainima: BLASTSyncEngine startSyncSet mActiveSyncs---:1
04-23 18:43:25.196 2077 4588 D jinyanmeiainima: java.lang.RuntimeException: jinyanmeiainima
04-23 18:43:25.196 2077 4588 D jinyanmeiainima: at com.android.server.wm.BLASTSyncEngine.startSyncSet(BLASTSyncEngine.java:327)
04-23 18:43:25.196 2077 4588 D jinyanmeiainima: at com.android.server.wm.BLASTSyncEngine.startSyncSet(BLASTSyncEngine.java:305)
04-23 18:43:25.196 2077 4588 D jinyanmeiainima: at com.android.server.wm.Transition.startCollecting(Transition.java:422)
04-23 18:43:25.196 2077 4588 D jinyanmeiainima: at com.android.server.wm.TransitionController.moveToCollecting(TransitionController.java:222)
04-23 18:43:25.196 2077 4588 D jinyanmeiainima: at com.android.server.wm.TransitionController.moveToCollecting(TransitionController.java:203)
04-23 18:43:25.196 2077 4588 D jinyanmeiainima: at com.android.server.wm.TransitionController.createTransition(TransitionController.java:197)
04-23 18:43:25.196 2077 4588 D jinyanmeiainima: at com.android.server.wm.TransitionController.createTransition(TransitionController.java:179)
04-23 18:43:25.196 2077 4588 D jinyanmeiainima: at com.android.server.wm.ActivityTaskSupervisor.findTaskToMoveToFront(ActivityTaskSupervisor.java:1577)
04-23 18:43:25.196 2077 4588 D jinyanmeiainima: at com.android.server.wm.ActivityTaskManagerService.moveTaskToFrontLocked(ActivityTaskManagerService.java:2497)
04-23 18:43:25.196 2077 4588 D jinyanmeiainima: at com.android.server.wm.ActivityTaskSupervisor.startActivityFromRecents(ActivityTaskSupervisor.java:3034)
04-23 18:43:25.196 2077 4588 D jinyanmeiainima: at com.android.server.wm.ActivityTaskManagerService.startActivityFromRecents(ActivityTaskManagerService.java:1918)
04-23 18:43:25.196 2077 4588 D jinyanmeiainima: at android.app.IActivityTaskManager$Stub.onTransact(IActivityTaskManager.java:1434)
04-23 18:43:25.196 2077 4588 D jinyanmeiainima: at com.android.server.wm.ActivityTaskManagerService.onTransact(ActivityTaskManagerService.java:5840)
04-23 18:43:25.196 2077 4588 D jinyanmeiainima: at android.os.Binder.execTransactInternal(Binder.java:1348)
04-23 18:43:25.196 2077 4588 D jinyanmeiainima: at android.os.Binder.execTransact(Binder.java:1279)new出来后调用task.mTransitionController.collect(task);04-24 16:06:47.682 1815 2160 D jinyanmeiani: ChangeInfo 111111111 this:Task{fa5361 #69 type=standard A=10143:comgallery.home}
04-24 16:06:47.682 1815 2160 D jinyanmeiani: ChangeInfo 111111111 mVisible:true
04-24 16:06:47.682 1815 2160 D jinyanmeiani: ChangeInfo 111111111 mWindowingMode:5
04-24 16:06:47.682 1815 2160 D jinyanmeiani: java.lang.RuntimeException: jinyanmeiani
04-24 16:06:47.682 1815 2160 D jinyanmeiani: at com.android.server.wm.Transition$ChangeInfo.<init>(Transition.java:2258)
04-24 16:06:47.682 1815 2160 D jinyanmeiani: at com.android.server.wm.Transition.collect(Transition.java:492)
04-24 16:06:47.682 1815 2160 D jinyanmeiani: at com.android.server.wm.TransitionController.collect(TransitionController.java:568)
04-24 16:06:47.682 1815 2160 D jinyanmeiani: at com.android.server.wm.ActivityTaskSupervisor.findTaskToMoveToFront(ActivityTaskSupervisor.java:1529)
04-24 16:06:47.682 1815 2160 D jinyanmeiani: at com.android.server.wm.ActivityTaskManagerService.moveTaskToFrontLocked(ActivityTaskManagerService.java:2464)
04-24 16:06:47.682 1815 2160 D jinyanmeiani: at com.android.server.wm.ActivityTaskSupervisor.startActivityFromRecents(ActivityTaskSupervisor.java:2901)
04-24 16:06:47.682 1815 2160 D jinyanmeiani: at com.android.server.wm.ActivityTaskManagerService.startActivityFromRecents(ActivityTaskManagerService.java:1931)
04-24 16:06:47.682 1815 2160 D jinyanmeiani: at android.app.IActivityTaskManager$Stub.onTransact(IActivityTaskManager.java:1430)
04-24 16:06:47.682 1815 2160 D jinyanmeiani: at com.android.server.wm.ActivityTaskManagerService.onTransact(ActivityTaskManagerService.java:5786)
04-24 16:06:47.682 1815 2160 D jinyanmeiani: at android.os.Binder.execTransactInternal(Binder.java:1348)
04-24 16:06:47.682 1815 2160 D jinyanmeiani: at android.os.Binder.execTransact(Binder.java:1279)
java">/** @see Transition#collect */
void collect(@NonNull WindowContainer wc) {if (mCollectingTransition == null) return;mCollectingTransition.collect(wc);
}

计算所有的到mChanges

根据WindowContainer new 一个ChangeInfo

java">ChangeInfo(@NonNull WindowContainer origState) {mContainer = origState;mVisible = origState.isVisibleRequested();mWindowingMode = origState.getWindowingMode();mAbsoluteBounds.set(origState.getBounds());mShowWallpaper = origState.showWallpaper();mRotation = origState.getWindowConfiguration().getRotation();mStartParent = origState.getParent();
}

把changeinfo放入mChanges

mChanges是一个map

key:WindowContainer

value:由key:WindowContainer构成的ChangeInfo

此列表在开始做动画时候会判断里面的key,value是否满足做动画的条件

java">void collect(@NonNull WindowContainer wc) {if (mState < STATE_COLLECTING) {throw new IllegalStateException("Transition hasn't started collecting.");}if (!isCollecting()) {// Too late, transition already started playing, so don't collect.return;}ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, "Collecting in transition %d: %s",mSyncId, wc);// "snapshot" all parents (as potential promotion targets). Do this before checking// if this is already a participant in case it has since been re-parented.for (WindowContainer<?> curr = getAnimatableParent(wc);curr != null && !mChanges.containsKey(curr);curr = getAnimatableParent(curr)) {mChanges.put(curr, new ChangeInfo(curr)); // 放入队列中if (isReadyGroup(curr)) {mReadyTracker.addGroup(curr);ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, " Creating Ready-group for"+ " Transition %d with root=%s", mSyncId, curr);}}if (mParticipants.contains(wc)) return;// Wallpaper is like in a static drawn state unless display may have changes, so exclude// the case to reduce transition latency waiting for the unchanged wallpaper to redraw.final boolean needSyncDraw = !isWallpaper(wc) || mParticipants.contains(wc.mDisplayContent);if (needSyncDraw) {mSyncEngine.addToSyncSet(mSyncId, wc);}ChangeInfo info = mChanges.get(wc);if (info == null) {info = new ChangeInfo(wc);Slog.d("jinyanmeiainima","collect                  wc:" + wc );Slog.d("jinyanmeiainima","collect             info:" + info );Slog.d("jinyanmeiainima","collect mChanges.size()+++:" + mChanges.size() );mChanges.put(wc, info);Slog.d("jinyanmeiainima","collect mChanges.size()---:" + mChanges.size() );}mParticipants.add(wc);if (wc.getDisplayContent() != null && !mTargetDisplays.contains(wc.getDisplayContent())) {mTargetDisplays.add(wc.getDisplayContent());}if (info.mShowWallpaper) {// Collect the wallpaper token (for isWallpaper(wc)) so it is part of the sync set.final WindowState wallpaper =wc.getDisplayContent().mWallpaperController.getTopVisibleWallpaper();if (wallpaper != null) {collect(wallpaper.mToken);}}}
java">把new出来的动画申请开始动画requestStartTransition04-23 18:43:25.211 2077 4588 D jinyanmeiainima: requestStartTransition displayChange:
04-23 18:43:25.211 2077 4588 D jinyanmeiainima: java.lang.RuntimeException: jinyanmeiainima
04-23 18:43:25.211 2077 4588 D jinyanmeiainima: at com.android.server.wm.TransitionController.requestStartTransition(TransitionController.java:548)
04-23 18:43:25.211 2077 4588 D jinyanmeiainima: at com.android.server.wm.ActivityTaskSupervisor.findTaskToMoveToFront(ActivityTaskSupervisor.java:1622)
04-23 18:43:25.211 2077 4588 D jinyanmeiainima: at com.android.server.wm.ActivityTaskManagerService.moveTaskToFrontLocked(ActivityTaskManagerService.java:2497)
04-23 18:43:25.211 2077 4588 D jinyanmeiainima: at com.android.server.wm.ActivityTaskSupervisor.startActivityFromRecents(ActivityTaskSupervisor.java:3034)
04-23 18:43:25.211 2077 4588 D jinyanmeiainima: at com.android.server.wm.ActivityTaskManagerService.startActivityFromRecents(ActivityTaskManagerService.java:1918)
04-23 18:43:25.211 2077 4588 D jinyanmeiainima: at android.app.IActivityTaskManager$Stub.onTransact(IActivityTaskManager.java:1434)
04-23 18:43:25.211 2077 4588 D jinyanmeiainima: at com.android.server.wm.ActivityTaskManagerService.onTransact(ActivityTaskManagerService.java:5840)
04-23 18:43:25.211 2077 4588 D jinyanmeiainima: at android.os.Binder.execTransactInternal(Binder.java:1348)
04-23 18:43:25.211 2077 4588 D jinyanmeiainima: at android.os.Binder.execTransact(Binder.java:1279)
java">Transition requestStartTransition(@NonNull Transition transition, @Nullable Task startTask,@Nullable RemoteTransition remoteTransition,@Nullable TransitionRequestInfo.DisplayChange displayChange) {Slog.d("jinyanmeiainima","requestStartTransition transition:" + transition );Slog.d("jinyanmeiainima","requestStartTransition startTask:" + startTask );Slog.d("jinyanmeiainima","requestStartTransition remoteTransition:" + remoteTransition );Slog.d("jinyanmeiainima","requestStartTransition displayChange:" + displayChange );if (mIsWaitingForDisplayEnabled) {ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, "Disabling player for transition"+ " #%d because display isn't enabled yet", transition.getSyncId());transition.mIsPlayerEnabled = false;transition.mLogger.mRequestTimeNs = SystemClock.uptimeNanos();mAtm.mH.post(() -> mAtm.mWindowOrganizerController.startTransition(transition.getToken(), null));return transition;}if (mTransitionPlayer == null || transition.isAborted()) {// Apparently, some tests will kill(and restart) systemui, so there is a chance that// the player might be transiently null.if (transition.isCollecting()) {transition.abort();}return transition;}try {ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS,"Requesting StartTransition: %s", transition);ActivityManager.RunningTaskInfo info = null;if (startTask != null) {info = new ActivityManager.RunningTaskInfo();startTask.fillTaskInfo(info);}final TransitionRequestInfo request = new TransitionRequestInfo(transition.mType, info, remoteTransition, displayChange);transition.mLogger.mRequestTimeNs = SystemClock.elapsedRealtimeNanos();transition.mLogger.mRequest = request;Slog.d("jinyanmeiainima","requestStartTransition transition.getToken():" + transition.getToken() );Slog.d("jinyanmeiainima","requestStartTransition               request:" + request);Slog.d("jinyanmeiainima","requestStartTransition displayChange:" ,  new RuntimeException("jinyanmeiainima") );mTransitionPlayer.requestStartTransition(transition.getToken(), request);transition.setRemoteTransition(remoteTransition);} catch (RemoteException e) {Slog.e(TAG, "Error requesting transition", e);transition.start();}return transition;
}

转到shell:

Transition requestStartTransition(@NonNull Transition transition, @Nullable Task startTask,

java">requestStartTransitionmTransitionPlayer.requestStartTransition(transition.getToken(), request);transition.setRemoteTransition(remoteTransition);

shell

java">   @BinderThreadprivate class TransitionPlayerImpl extends ITransitionPlayer.Stub {@Overridepublic void onTransitionReady(IBinder iBinder, TransitionInfo transitionInfo,SurfaceControl.Transaction t, SurfaceControl.Transaction finishT)throws RemoteException {mMainExecutor.execute(() -> Transitions.this.onTransitionReady(iBinder, transitionInfo, t, finishT));}@Overridepublic void requestStartTransition(IBinder iBinder,TransitionRequestInfo request) throws RemoteException {mMainExecutor.execute(() -> Transitions.this.requestStartTransition(iBinder, request));}}
}
java">void requestStartTransition(@NonNull IBinder transitionToken,@Nullable TransitionRequestInfo request) {ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "Transition requested: %s %s",transitionToken, request);if (isTransitionKnown(transitionToken)) {throw new RuntimeException("Transition already started " + transitionToken);}final ActiveTransition active = new ActiveTransition();WindowContainerTransaction wct = null;// If we have sleep, we use a special handler and we try to finish everything ASAP.if (request.getType() == TRANSIT_SLEEP) {mSleepHandler.handleRequest(transitionToken, request);active.mHandler = mSleepHandler;} else {for (int i = mHandlers.size() - 1; i >= 0; --i) {wct = mHandlers.get(i).handleRequest(transitionToken, request);if (wct != null) {active.mHandler = mHandlers.get(i);break;}}if (request.getDisplayChange() != null) {TransitionRequestInfo.DisplayChange change = request.getDisplayChange();if (change.getEndRotation() != change.getStartRotation()) {// Is a rotation, so dispatch to all displayChange listenersif (wct == null) {wct = new WindowContainerTransaction();}mDisplayController.getChangeController().dispatchOnDisplayChange(wct,change.getDisplayId(), change.getStartRotation(),change.getEndRotation(), null /* newDisplayAreaInfo */);}}}mOrganizer.startTransition(transitionToken, wct != null && wct.isEmpty() ? null : wct);active.mToken = transitionToken;// Currently, WMCore only does one transition at a time. If it makes a requestStart, it// is already collecting that transition on core-side, so it will be the next one to// become ready. There may already be pending transitions added as part of direct// `startNewTransition` but if we have a request now, it means WM created the request// transition before it acknowledged any of the pending `startNew` transitions. So, insert// it at the front.mPendingTransitions.add(0, active);  // 添加到mPendingTransitions
}
java">private static final class ActiveTransition {IBinder mToken;TransitionHandler mHandler;boolean mAborted;TransitionInfo mInfo;SurfaceControl.Transaction mStartT;SurfaceControl.Transaction mFinishT;/** Ordered list of transitions which have been merged into this one. */private ArrayList<ActiveTransition> mMerged;
}
java">转到wm core04-23 18:43:22.342 2980 3221 D jinyanmeiainima: WindowOrganizer transitionToken transitionToken:android.os.BinderProxy@3268f3
04-23 18:43:22.343 2980 3221 D jinyanmeiainima: WindowOrganizer startTransition t:null
04-23 18:43:22.343 2980 3221 D jinyanmeiainima: java.lang.RuntimeException: jinyanmeiainima
04-23 18:43:22.343 2980 3221 D jinyanmeiainima: at android.window.WindowOrganizer.startTransition(WindowOrganizer.java:112)
04-23 18:43:22.343 2980 3221 D jinyanmeiainima: at com.android.wm.shell.transition.Transitions.requestStartTransition(Transitions.java:891)
04-23 18:43:22.343 2980 3221 D jinyanmeiainima: at com.android.wm.shell.transition.Transitions$TransitionPlayerImpl.lambda$requestStartTransition$1(Transitions.java:1129)
04-23 18:43:22.343 2980 3221 D jinyanmeiainima: at com.android.wm.shell.transition.Transitions$TransitionPlayerImpl.$r8$lambda$FkH1M0vUh3zDx8R5iMruInPEXLI(Unknown Source:0)
04-23 18:43:22.343 2980 3221 D jinyanmeiainima: at com.android.wm.shell.transition.Transitions$TransitionPlayerImpl$$ExternalSyntheticLambda1.run(Unknown Source:6)
04-23 18:43:22.343 2980 3221 D jinyanmeiainima: at android.os.Handler.handleCallback(Handler.java:958)
04-23 18:43:22.343 2980 3221 D jinyanmeiainima: at android.os.Handler.dispatchMessage(Handler.java:99)
04-23 18:43:22.343 2980 3221 D jinyanmeiainima: at android.os.Looper.loopOnce(Looper.java:216)
04-23 18:43:22.343 2980 3221 D jinyanmeiainima: at android.os.Looper.loop(Looper.java:305)
04-23 18:43:22.343 2980 3221 D jinyanmeiainima: at android.os.HandlerThread.run(HandlerThread.java:67)
java"> WindowOrganizer.java
@RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS)public void startTransition(@NonNull IBinder transitionToken,@Nullable WindowContainerTransaction t) {try {getWindowOrganizerController().startTransition(transitionToken, t);} catch (RemoteException e) {throw e.rethrowFromSystemServer();}}
转到 wm services
WindowOrganizerController
java">WindowOrganizerController.java   
private IBinder startTransition(@WindowManager.TransitionType int type,@Nullable IBinder transitionToken, @Nullable WindowContainerTransaction t) {enforceTaskPermission("startTransition()");final CallerInfo caller = new CallerInfo();final long ident = Binder.clearCallingIdentity();try {synchronized (mGlobalLock) {Transition transition = Transition.fromBinder(transitionToken);if (mTransitionController.getTransitionPlayer() == null && transition == null) {Slog.w(TAG, "Using shell transitions API for legacy transitions.");if (t == null) {throw new IllegalArgumentException("Can't use legacy transitions in"+ " compatibility mode with no WCT.");}applyTransaction(t, -1 /* syncId */, null, caller);return null;}// In cases where transition is already provided, the "readiness lifecycle" of the// transition is determined outside of this transaction. However, if this is a// direct call from shell, the entire transition lifecycle is contained in the// provided transaction and thus we can setReady immediately after apply.final boolean needsSetReady = transition == null && t != null;final WindowContainerTransaction wct =t != null ? t : new WindowContainerTransaction();if (transition == null) {if (type < 0) {throw new IllegalArgumentException("Can't create transition with no type");}// If there is already a collecting transition, queue up a new transition and// return that. The actual start and apply will then be deferred until that// transition starts collecting. This should almost never happen except during// tests.if (mService.mWindowManager.mSyncEngine.hasActiveSync()) {Slog.w(TAG, "startTransition() while one is already collecting.");final Transition nextTransition = new Transition(type, 0 /* flags */,mTransitionController, mService.mWindowManager.mSyncEngine);ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS,"Creating Pending Transition: %s", nextTransition);mService.mWindowManager.mSyncEngine.queueSyncSet(// Make sure to collect immediately to prevent another transition// from sneaking in before it. Note: moveToCollecting internally// calls startSyncSet.() -> mTransitionController.moveToCollecting(nextTransition),() -> {nextTransition.start();applyTransaction(wct, -1 /*syncId*/, nextTransition, caller);if (needsSetReady) {nextTransition.setAllReady();}});return nextTransition.getToken();}transition = mTransitionController.createTransition(type);}if (!transition.isCollecting() && !transition.isForcePlaying()) {Slog.e(TAG, "Trying to start a transition that isn't collecting. This probably"+ " means Shell took too long to respond to a request. WM State may be"+ " incorrect now, please file a bug");applyTransaction(wct, -1 /*syncId*/, null /*transition*/, caller);return transition.getToken();}transition.start();  /到这里transition.mLogger.mStartWCT = wct;applyTransaction(wct, -1 /*syncId*/, transition, caller);if (needsSetReady) {transition.setAllReady();}return transition.getToken();}} finally {Binder.restoreCallingIdentity(ident);}}

04-23 18:44:02.186 2107 2323 D jinyanmeiainima: BLASTSyncEngine setReady ready:true
04-23 18:44:02.186 2107 2323 D jinyanmeiainima: java.lang.RuntimeException: setReady
04-23 18:44:02.186 2107 2323 D jinyanmeiainima: at com.android.server.wm.BLASTSyncEngine$SyncGroup.setReady(BLASTSyncEngine.java:240)
04-23 18:44:02.186 2107 2323 D jinyanmeiainima: at com.android.server.wm.BLASTSyncEngine$SyncGroup.-$$Nest$msetReady(Unknown Source:0)
04-23 18:44:02.186 2107 2323 D jinyanmeiainima: at com.android.server.wm.BLASTSyncEngine.setReady(BLASTSyncEngine.java:356)
04-23 18:44:02.186 2107 2323 D jinyanmeiainima: at com.android.server.wm.Transition.applyReady(Transition.java:657)
04-23 18:44:02.186 2107 2323 D jinyanmeiainima: at com.android.server.wm.Transition.start(Transition.java:446)
04-23 18:44:02.186 2107 2323 D jinyanmeiainima: at com.android.server.wm.WindowOrganizerController.startTransition(WindowOrganizerController.java:335)
04-23 18:44:02.186 2107 2323 D jinyanmeiainima: at com.android.server.wm.WindowOrganizerController.startTransition(WindowOrganizerController.java:267)
04-23 18:44:02.186 2107 2323 D jinyanmeiainima: at android.window.IWindowOrganizerController$Stub.onTransact(IWindowOrganizerController.java:264)
04-23 18:44:02.186 2107 2323 D jinyanmeiainima: at com.android.server.wm.WindowOrganizerController.onTransact(WindowOrganizerController.java:185)
04-23 18:44:02.186 2107 2323 D jinyanmeiainima: at android.os.Binder.execTransactInternal(Binder.java:1343)
04-23 18:44:02.186 2107 2323 D jinyanmeiainima: at android.os.Binder.execTransact(Binder.java:1279)

然后调用到BLASTSyncEngine setReady 将动画状态置为ready

开始刷新

java">  BLASTSyncEngine.java     
private void setReady(boolean ready) {if (mReady == ready) {return;}Slog.d("jinyanmeiainima","BLASTSyncEngine setReady              ready:" + ready, new RuntimeException("setReady"));ProtoLog.v(WM_DEBUG_SYNC_ENGINE, "SyncGroup %d: Set ready", mSyncId);mReady = ready;if (!ready) return;mWm.mWindowPlacerLocked.requestTraversal();}
java">private static final class ActiveTransition {IBinder mToken;TransitionHandler mHandler;boolean mAborted;TransitionInfo mInfo;SurfaceControl.Transaction mStartT;SurfaceControl.Transaction mFinishT;/** Ordered list of transitions which have been merged into this one. */private ArrayList<ActiveTransition> mMerged;
}

onTransactionReady阶段

2.1 数据准备,筛选要做动画的对象

刷新时调用到 wm services. onTransactionReady 

java">04-23 18:43:22.529 2073 2100 D jinyanmeiainima: Transition onTransactionReady mToken:Token{a674b32 TransitionRecord{d9c7094 id=6 type=TO_FRONT flags=0}}04-23 18:43:22.529 2073 2100 D jinyanmeiainima: Transition onTransactionReady info:{t=TO_FRONT f=0x0 ro=Point(0, 0) c=[{WCT{RemoteToken{2a5ead1 Task{c299c5e #39 type=standard A=10245:com..notes}}} m=SHOW f=TRANSLUCENT leash=Surface(name=Task=39)/@0x2c4c3d4 sb=Rect(0, 0 - 1800, 2880) eb=Rect(799, 141 - 1759, 1848) eo=Point(799, 141)}]}
04-23 18:43:22.529 2073 2100 D jinyanmeiainima: Transition onTransactionReady transaction:android.view.SurfaceControl$Transaction@65dbba
04-23 18:43:22.529 2073 2100 D jinyanmeiainima: Transition onTransactionReady mFinishTransaction:android.view.SurfaceControl$Transaction@2d6a6b
04-23 18:43:22.529 2073 2100 D jinyanmeiainima: java.lang.RuntimeException: jinyanmeiainima
04-23 18:43:22.529 2073 2100 D jinyanmeiainima: at com.android.server.wm.Transition.onTransactionReady(Transition.java:1215)
04-23 18:43:22.529 2073 2100 D jinyanmeiainima: at com.android.server.wm.BLASTSyncEngine$SyncGroup.finishNow(BLASTSyncEngine.java:206) //这里会从队列移除
04-23 18:43:22.529 2073 2100 D jinyanmeiainima: at com.android.server.wm.BLASTSyncEngine$SyncGroup.onSurfacePlacement(BLASTSyncEngine.java:148)
04-23 18:43:22.529 2073 2100 D jinyanmeiainima: at com.android.server.wm.BLASTSyncEngine$SyncGroup.-$$Nest$monSurfacePlacement(Unknown Source:0)
04-23 18:43:22.529 2073 2100 D jinyanmeiainima: at com.android.server.wm.BLASTSyncEngine.onSurfacePlacement(BLASTSyncEngine.java:382)
04-23 18:43:22.529 2073 2100 D jinyanmeiainima: at com.android.server.wm.RootWindowContainer.performSurfacePlacementNoTrace(RootWindowContainer.java:893)
04-23 18:43:22.529 2073 2100 D jinyanmeiainima: at com.android.server.wm.RootWindowContainer.performSurfacePlacement(RootWindowContainer.java:836)
04-23 18:43:22.529 2073 2100 D jinyanmeiainima: at com.android.server.wm.WindowSurfacePlacer.performSurfacePlacementLoop(WindowSurfacePlacer.java:200)
04-23 18:43:22.529 2073 2100 D jinyanmeiainima: at com.android.server.wm.WindowSurfacePlacer.performSurfacePlacement(WindowSurfacePlacer.java:149)
04-23 18:43:22.529 2073 2100 D jinyanmeiainima: at com.android.server.wm.WindowSurfacePlacer.performSurfacePlacement(WindowSurfacePlacer.java:138)
04-23 18:43:22.529 2073 2100 D jinyanmeiainima: at com.android.server.wm.WindowSurfacePlacer$Traverser.run(WindowSurfacePlacer.java:80)
04-23 18:43:22.529 2073 2100 D jinyanmeiainima: at android.os.Handler.handleCallback(Handler.java:958)
04-23 18:43:22.529 2073 2100 D jinyanmeiainima: at android.os.Handler.dispatchMessage(Handler.java:99)
04-23 18:43:22.529 2073 2100 D jinyanmeiainima: at android.os.Looper.loopOnce(Looper.java:216)
04-23 18:43:22.529 2073 2100 D jinyanmeiainima: at android.os.Looper.loop(Looper.java:305)
04-23 18:43:22.529 2073 2100 D jinyanmeiainima: at android.os.HandlerThread.run(HandlerThread.java:67)
04-23 18:43:22.529 2073 2100 D jinyanmeiainima: at com.android.server.ServiceThread.run(ServiceThread.java:46)
java">
BLASTSyncEngine.java
private void finishNow() {mActiveSyncs.remove(mSyncId); //从队列移除}

Transition.onTransactionReady

mTargets = calculateTargets(mParticipants, mChanges); //计算mTargets

根据target 计算info
final TransitionInfo info = calculateTransitionInfo(mType, mFlags, mTargets, transaction);

java">Transition.java
public void onTransactionReady(int syncId, SurfaceControl.Transaction transaction) {final ArrayMap<WindowContainer, ChangeInfo> mChanges = new ArrayMap<>(); //这里的mChanges 也是一个mapmTargets = calculateTargets(mParticipants, mChanges);final TransitionInfo info = calculateTransitionInfo(mType, mFlags, mTargets, transaction);mController.getTransitionPlayer().onTransitionReady(mToken, info, transaction, mFinishTransaction);if (Trace.isTagEnabled(TRACE_TAG_WINDOW_MANAGER)) {Trace.asyncTraceBegin(TRACE_TAG_WINDOW_MANAGER, TRACE_NAME_PLAY_TRANSITION,}

wm.services.Transition.calculateTargets

两个条件不添加动画:

1:!wc.isAttached()

2:!changeInfo.hasChanged()

将符合条件的changeInfo添加到targets 返回

java">@VisibleForTesting
@NonNull
static ArrayList<ChangeInfo> calculateTargets(ArraySet<WindowContainer> participants,ArrayMap<WindowContainer, ChangeInfo> changes) {ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS,"Start calculating TransitionInfo based on participants: %s", participants);// Add all valid participants to the target container.final Targets targets = new Targets();for (int i = participants.size() - 1; i >= 0; --i) {final WindowContainer<?> wc = participants.valueAt(i);if (!wc.isAttached()) {    ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS,"  Rejecting as detached: %s", wc);continue;}// The level of transition target should be at least window token.if (wc.asWindowState() != null) continue;final ChangeInfo changeInfo = changes.get(wc); // changes即mChanges,由onTransitionReady时添加到changes 的map //这里的changeInfo 与TransitionInfo不是一个// Reject no-opsif (!changeInfo.hasChanged()) {ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS,"  Rejecting as no-op: %s", wc);continue;}targets.add(changeInfo);}ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, "  Initial targets: %s",targets.mArray);// Combine the targets from bottom to top if possible.tryPromote(targets, changes);// Establish the relationship between the targets and their top changes.populateParentChanges(targets, changes);final ArrayList<ChangeInfo> targetList = targets.getListSortedByZ();ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, "  Final targets: %s", targetList);return targetList;
}
java">
boolean hasChanged() {// the task including transient launch must promote to root taskif ((mFlags & ChangeInfo.FLAG_TRANSIENT_LAUNCH) != 0|| (mFlags & ChangeInfo.FLAG_ABOVE_TRANSIENT_LAUNCH) != 0) {return true;}// If it's invisible and hasn't changed visibility, always return false since even if// something changed, it wouldn't be a visible change.final boolean currVisible = mContainer.isVisibleRequested();if (currVisible == mVisible && !mVisible) return false;return currVisible != mVisible|| mKnownConfigChanges != 0// if mWindowingMode is 0, this container wasn't attached at collect time, so// assume no change in windowing-mode.|| (mWindowingMode != 0 && mContainer.getWindowingMode() != mWindowingMode)|| !mContainer.getBounds().equals(mAbsoluteBounds)|| mRotation != mContainer.getWindowConfiguration().getRotation();}

根据上步计算出来的sortedTargets计算要做的动画TransitionInfo

TransitionInfo中有个mChanges

java">public final class TransitionInfo implements Parcelable {/*** Modes are only a sub-set of all the transit-types since they are per-container* @hide*/@IntDef(prefix = { "TRANSIT_" }, value = {TRANSIT_NONE,TRANSIT_OPEN,TRANSIT_CLOSE,// Note: to_front/to_back really mean show/hide respectively at the container level.TRANSIT_TO_FRONT,TRANSIT_TO_BACK,TRANSIT_CHANGE})public @interface TransitionMode {}private final ArrayList<Change> mChanges = new ArrayList<>();
java">public static final class Change implements Parcelable {private final WindowContainerToken mContainer;private WindowContainerToken mParent;private WindowContainerToken mLastParent;private final SurfaceControl mLeash;private @TransitionMode int mMode = TRANSIT_NONE;private @ChangeFlags int mFlags = FLAG_NONE;private final Rect mStartAbsBounds = new Rect();private final Rect mEndAbsBounds = new Rect();private final Point mEndRelOffset = new Point();private ActivityManager.RunningTaskInfo mTaskInfo = null;private boolean mAllowEnterPip;private @Surface.Rotation int mStartRotation = ROTATION_UNDEFINED;private @Surface.Rotation int mEndRotation = ROTATION_UNDEFINED;/*** The end rotation of the top activity after fixed rotation is finished. If the top* activity is not in fixed rotation, it will be {@link ROTATION_UNDEFINED}.*/private @Surface.Rotation int mEndFixedRotation = ROTATION_UNDEFINED;private int mRotationAnimation = ROTATION_ANIMATION_UNSPECIFIED;private @ColorInt int mBackgroundColor;private SurfaceControl mSnapshot = null;private float mSnapshotLuma;
java">static TransitionInfo calculateTransitionInfo(@TransitionType int type, int flags,ArrayList<ChangeInfo> sortedTargets,@Nullable SurfaceControl.Transaction startT) {final TransitionInfo out = new TransitionInfo(type, flags);  //根据type 和flags 构建新的TransitionInfo 对象WindowContainer<?> topApp = null;for (int i = 0; i < sortedTargets.size(); i++) {final WindowContainer<?> wc = sortedTargets.get(i).mContainer;if (!isWallpaper(wc)) {topApp = wc;break;}}if (topApp == null) {out.setRootLeash(new SurfaceControl(), 0, 0);return out;}WindowContainer<?> ancestor = findCommonAncestor(sortedTargets, topApp);// Make leash based on highest (z-order) direct child of ancestor with a participant.// TODO(b/261418859): Handle the case when the target contains window containers which// belong to a different display. As a workaround we use topApp, from which wallpaper// window container is removed, instead of sortedTargets here.WindowContainer leashReference = topApp;while (leashReference.getParent() != ancestor) {leashReference = leashReference.getParent();}final SurfaceControl rootLeash = leashReference.makeAnimationLeash().setName("Transition Root: " + leashReference.getName()).build();startT.setLayer(rootLeash, leashReference.getLastLayer());                              // 设置layerout.setRootLeash(rootLeash, ancestor.getBounds().left, ancestor.getBounds().top);    //设置leash// Convert all the resolved ChangeInfos into TransactionInfo.Change objects in order.final int count = sortedTargets.size();                      //遍历上一步筛选出来的sortedTargetsfor (int i = 0; i < count; ++i) {final ChangeInfo info = sortedTargets.get(i);final WindowContainer target = info.mContainer;final TransitionInfo.Change change = new TransitionInfo.Change(target.mRemoteToken != null ? target.mRemoteToken.toWindowContainerToken()     //根据windwoContainer的成员变量mWindowContainerToken 构建一个change所以每个windwoContainer都有一个change: null, getLeashSurface(target, startT));// TODO(shell-transitions): Use leash for non-organized windows.if (info.mEndParent != null) {change.setParent(info.mEndParent.mRemoteToken.toWindowContainerToken());}if (info.mStartParent != null && info.mStartParent.mRemoteToken != null&& target.getParent() != info.mStartParent) {change.setLastParent(info.mStartParent.mRemoteToken.toWindowContainerToken());}change.setMode(info.getTransitMode(target));change.setStartAbsBounds(info.mAbsoluteBounds);change.setFlags(info.getChangeFlags(target));final Task task = target.asTask();final TaskFragment taskFragment = target.asTaskFragment();final ActivityRecord activityRecord = target.asActivityRecord();if (task != null) {final ActivityManager.RunningTaskInfo tinfo = new ActivityManager.RunningTaskInfo();task.fillTaskInfo(tinfo);change.setTaskInfo(tinfo);change.setRotationAnimation(getTaskRotationAnimation(task));final ActivityRecord topMostActivity = task.getTopMostActivity();change.setAllowEnterPip(topMostActivity != null&& topMostActivity.checkEnterPictureInPictureAppOpsState());final ActivityRecord topRunningActivity = task.topRunningActivity();if (topRunningActivity != null && task.mDisplayContent != null// Display won't be rotated for multi window Task, so the fixed rotation// won't be applied. This can happen when the windowing mode is changed// before the previous fixed rotation is applied.&& !task.inMultiWindowMode()) {// If Activity is in fixed rotation, its will be applied with the next rotation,// when the Task is still in the previous rotation.final int taskRotation = task.getWindowConfiguration().getDisplayRotation();final int activityRotation = topRunningActivity.getWindowConfiguration().getDisplayRotation();if (taskRotation != activityRotation) {change.setEndFixedRotation(activityRotation);}}} else if ((info.mFlags & ChangeInfo.FLAG_SEAMLESS_ROTATION) != 0) {change.setRotationAnimation(ROTATION_ANIMATION_SEAMLESS);}final WindowContainer<?> parent = target.getParent();final Rect bounds = target.getBounds();final Rect parentBounds = parent.getBounds();change.setEndRelOffset(bounds.left - parentBounds.left,bounds.top - parentBounds.top);int endRotation = target.getWindowConfiguration().getRotation();if (activityRecord != null) {// TODO(b/227427984): Shell needs to aware letterbox.// Always use parent bounds of activity because letterbox area (e.g. fixed aspect// ratio or size compat mode) should be included in the animation.change.setEndAbsBounds(parentBounds);if (activityRecord.getRelativeDisplayRotation() != 0&& !activityRecord.mTransitionController.useShellTransitionsRotation()) {// Use parent rotation because shell doesn't know the surface is rotated.endRotation = parent.getWindowConfiguration().getRotation();}} else {change.setEndAbsBounds(bounds);}if (activityRecord != null || (taskFragment != null && taskFragment.isEmbedded())) {final int backgroundColor;final TaskFragment organizedTf = activityRecord != null? activityRecord.getOrganizedTaskFragment(): taskFragment.getOrganizedTaskFragment();if (organizedTf != null && organizedTf.getAnimationParams().getAnimationBackgroundColor() != DEFAULT_ANIMATION_BACKGROUND_COLOR) {// This window is embedded and has an animation background color set on the// TaskFragment. Pass this color with this window, so the handler can use it as// the animation background color if needed,backgroundColor = organizedTf.getAnimationParams().getAnimationBackgroundColor();} else {// Set background color to Task theme color for activity and embedded// TaskFragment in case we want to show background during the animation.final Task parentTask = activityRecord != null? activityRecord.getTask(): taskFragment.getTask();backgroundColor = parentTask.getTaskDescription().getBackgroundColor();}// Set to opaque for animation background to prevent it from exposing the blank// background or content below.change.setBackgroundColor(ColorUtils.setAlphaComponent(backgroundColor, 255));}change.setRotation(info.mRotation, endRotation);if (info.mSnapshot != null) {change.setSnapshot(info.mSnapshot, info.mSnapshotLuma);}out.addChange(change);  //最后把widowContainer的change放入mChanger中out(TransitionInfo)中}TransitionInfo.AnimationOptions animOptions = null;if (topApp.asActivityRecord() != null) {final ActivityRecord topActivity = topApp.asActivityRecord();animOptions = addCustomActivityTransition(topActivity, true/* open */, null);animOptions = addCustomActivityTransition(topActivity, false/* open */, animOptions);}final WindowManager.LayoutParams animLp =getLayoutParamsForAnimationsStyle(type, sortedTargets);if (animLp != null && animLp.type != TYPE_APPLICATION_STARTING&& animLp.windowAnimations != 0) {// Don't send animation options if no windowAnimations have been set or if the we are// running an app starting animation, in which case we don't want the app to be able to// change its animation directly.if (animOptions != null) {animOptions.addOptionsFromLayoutParameters(animLp);} else {animOptions = TransitionInfo.AnimationOptions.makeAnimOptionsFromLayoutParameters(animLp);}}if (animOptions != null) {out.setAnimationOptions(animOptions);}return out;
}

2.2 开始动画

到shell.onTransitionReady

java">@BinderThread
private class TransitionPlayerImpl extends ITransitionPlayer.Stub {@Overridepublic void onTransitionReady(IBinder iBinder, TransitionInfo transitionInfo,SurfaceControl.Transaction t, SurfaceControl.Transaction finishT)throws RemoteException {mMainExecutor.execute(() -> Transitions.this.onTransitionReady(iBinder, transitionInfo, t, finishT));}@Overridepublic void requestStartTransition(IBinder iBinder,TransitionRequestInfo request) throws RemoteException {mMainExecutor.execute(() -> Transitions.this.requestStartTransition(iBinder, request));}
}
java">void onTransitionReady(@NonNull IBinder transitionToken, @NonNull TransitionInfo info,@NonNull SurfaceControl.Transaction t, @NonNull SurfaceControl.Transaction finishT) {ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "onTransitionReady %s: %s",transitionToken, info);final int activeIdx = findByToken(mPendingTransitions, transitionToken);if (activeIdx < 0) {throw new IllegalStateException("Got transitionReady for non-pending transition "+ transitionToken + ". expecting one of "+ Arrays.toString(mPendingTransitions.stream().map(activeTransition -> activeTransition.mToken).toArray()));}if (activeIdx > 0) {Log.e(TAG, "Transition became ready out-of-order " + transitionToken + ". Expected"+ " order: " + Arrays.toString(mPendingTransitions.stream().map(activeTransition -> activeTransition.mToken).toArray()));}// Move from pending to readyfinal ActiveTransition active = mPendingTransitions.remove(activeIdx);//从 mPendingTransitions 移除mReadyTransitions.add(active); //添加至 mReadyTransitionsactive.mInfo = info;active.mStartT = t;active.mFinishT = finishT;for (int i = 0; i < mObservers.size(); ++i) {mObservers.get(i).onTransitionReady(transitionToken, info, t, finishT);}if (info.getType() == TRANSIT_SLEEP) {if (activeIdx > 0) {if (!info.getRootLeash().isValid()) {// Shell has some debug settings which makes calling binders with invalid// surfaces crash, so replace it with a "real" one.info.setRootLeash(new SurfaceControl.Builder().setName("Invalid").setContainerLayer().build(), 0, 0);}// Sleep starts a process of forcing all prior transitions to finish immediatelyfinishForSleep(null /* forceFinish */);return;}}// Allow to notify keyguard un-occluding state to KeyguardService, which can happen while// screen-off, so there might no visibility change involved.if (!info.getRootLeash().isValid() && info.getType() != TRANSIT_KEYGUARD_UNOCCLUDE) {// Invalid root-leash implies that the transition is empty/no-op, so just do// housekeeping and return.ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "Invalid root leash (%s): %s",transitionToken, info);onAbort(active);return;}final int changeSize = info.getChanges().size(); //找到带有change的infoboolean taskChange = false;boolean transferStartingWindow = false;boolean allOccluded = changeSize > 0;for (int i = changeSize - 1; i >= 0; --i) {final TransitionInfo.Change change = info.getChanges().get(i);taskChange |= change.getTaskInfo() != null;transferStartingWindow |= change.hasFlags(FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT);if (!change.hasFlags(FLAG_IS_OCCLUDED)) {allOccluded = false;}}// There does not need animation when:// A. Transfer starting window. Apply transfer starting window directly if there is no other// task change. Since this is an activity->activity situation, we can detect it by selecting// transitions with only 2 changes where neither are tasks and one is a starting-window// recipient.if (!taskChange && transferStartingWindow && changeSize == 2// B. It's visibility change if the TRANSIT_TO_BACK/TO_FRONT happened when all// changes are underneath another change.|| ((info.getType() == TRANSIT_TO_BACK || info.getType() == TRANSIT_TO_FRONT)&& allOccluded)) {// Treat this as an abort since we are bypassing any merge logic and effectively// finishing immediately.onAbort(active);return;}setupStartState(active.mInfo, active.mStartT, active.mFinishT);    //开始置状态if (mReadyTransitions.size() > 1) {// There are already transitions waiting in the queue, so just return.return;}processReadyQueue();  //开始动画}
java">04-23 18:44:02.339 2107 2246 D jinyanmeiainima: BLASTSyncEngine finishNow s.mSyncId:5
04-23 18:44:02.339 2107 2246 D jinyanmeiainima: BLASTSyncEngine finishNow mActiveSyncs++++:1
04-23 18:44:02.339 2107 2246 D jinyanmeiainima: BLASTSyncEngine finishNow s.mSyncId:5
04-23 18:44:02.339 2107 2246 D jinyanmeiainima: BLASTSyncEngine finishNow mActiveSyncs++++:0
04-23 18:44:02.347 3002 3197 D jinyanmeiainima: startAnimation TRANSIT_CHANGE:
04-23 18:44:02.347 3002 3197 D jinyanmeiainima: java.lang.RuntimeException: jinyanmeiainima
04-23 18:44:02.347 3002 3197 D jinyanmeiainima: at com.android.wm.shell.transition.Transitions.dispatchTransition(Transitions.java:708)
04-23 18:44:02.347 3002 3197 D jinyanmeiainima: at com.android.wm.shell.transition.Transitions.playTransition(Transitions.java:693)
04-23 18:44:02.347 3002 3197 D jinyanmeiainima: at com.android.wm.shell.transition.Transitions.processReadyQueue(Transitions.java:627)
04-23 18:44:02.347 3002 3197 D jinyanmeiainima: at com.android.wm.shell.transition.Transitions.onTransitionReady(Transitions.java:600)
04-23 18:44:02.347 3002 3197 D jinyanmeiainima: at com.android.wm.shell.transition.Transitions$TransitionPlayerImpl.lambda$onTransitionReady$0(Transitions.java:1122)
04-23 18:44:02.347 3002 3197 D jinyanmeiainima: at com.android.wm.shell.transition.Transitions$TransitionPlayerImpl.$r8$lambda$qsRfWn1ItrZqnFeABBdxU50jPc4(Unknown Source:0)
04-23 18:44:02.347 3002 3197 D jinyanmeiainima: at com.android.wm.shell.transition.Transitions$TransitionPlayerImpl$$ExternalSyntheticLambda0.run(Unknown Source:10)
04-23 18:44:02.347 3002 3197 D jinyanmeiainima: at android.os.Handler.handleCallback(Handler.java:958)
04-23 18:44:02.347 3002 3197 D jinyanmeiainima: at android.os.Handler.dispatchMessage(Handler.java:99)
04-23 18:44:02.347 3002 3197 D jinyanmeiainima: at android.os.Looper.loopOnce(Looper.java:216)
04-23 18:44:02.347 3002 3197 D jinyanmeiainima: at android.os.Looper.loop(Looper.java:305)
04-23 18:44:02.347 3002 3197 D jinyanmeiainima: at android.os.HandlerThread.run(HandlerThread.java:67)

然后各个继承于

implements Transitions.TransitionHandler 的对象都会调用到startAnimation

走各个业务动画逻辑


http://www.ppmy.cn/embedded/19664.html

相关文章

【机器学习】集成学习:强化机器学习模型与创新能的利器

集成学习&#xff1a;强化机器学习模型预测性能的利器 一、集成学习的核心思想二、常用集成学习方法Bagging方法Boosting方法Stacking方法 三、集成学习代表模型与实现四、总结与展望 在大数据时代的浪潮下&#xff0c;机器学习模型的应用越来越广泛&#xff0c;而集成学习作为…

通义灵码-IDEA的使用教程

通义灵码-IDEA的使用教程 1、通义灵码是什么&#xff1f; 通义灵码&#xff0c;是阿里云出品的一款基于通义大模型的智能编码辅助工具&#xff0c;提供行级/函数级实时续写、自然语言生成代码、单元测试生成、代码注释生成、代码解释、研发智能问答、异常报错排查等能力&#…

SpringBoot

SpringBoot 第一部分 SpringBoot应用 相关概念 约定优于配置 约定优于配置(Convention over Configuration)&#xff0c;又称按约定编程&#xff0c;是一种软件设计规范。 本质上是对系统、类库或框架中一些东西假定一个大众化合理的默认值(缺省值)。 例如在模型中存在一…

计算机存储原理.2

1.主存储器与CPU之间的连接 2.存储器芯片的输入输出信号 3.增加主存的存储字长 3.1位扩展 数据总线的利用成分是不充分的(单块只能读写一位)&#xff0c;为了解决这个问题所以引出了位扩展。 使用多块存储芯片解决这个问题。 3.2字扩展 因为存储器买的是8k*8位的&am…

创新入门|从点击到转化:AI个性化登陆页助力潜在客户转化

在数字营销的竞争格局中&#xff0c;采用先进技术对于旨在区分自己并吸引受众的企业至关重要。人工智能 &#xff08;AI&#xff09; 成为一项关键技术&#xff0c;尤其是在制作个性化登录页面的艺术方面。这些页面不仅仅是品牌与其潜在客户之间的第一个接触点;它们是吸引兴趣、…

ASP.Net MVC 登录页面实现RSA非对称加密

一、什么是RSA非对称加密 RSA是1977年由罗纳德李维斯特&#xff08;Ron Rivest&#xff09;、阿迪萨莫尔&#xff08;Adi Shamir&#xff09;和伦纳德阿德曼&#xff08;Leonard Adleman&#xff09;一起提出的。 RSA算法是一种非对称加密算法&#xff0c;与对称加密算法不同…

MATLAB矩阵

MATLAB 矩阵 矩阵是数字的二维数组。 在MATLAB中&#xff0c;您可以通过在每行中以逗号或空格分隔的数字输入元素并使用分号标记每行的结尾来创建矩阵。 例如&#xff0c;让我们创建一个45矩阵一- 示例 a [ 1 2 3 4 5; 2 3 4 5 6; 3 4 5 6 7; 4 5 6 7 8] MATLAB将执行上述语…

深入理解MySQL的MVCC(多版本并发控制)

在MySQL中&#xff0c;MVCC&#xff08;Multi-Version Concurrency Control&#xff0c;多版本并发控制&#xff09;是一个重要的特性&#xff0c;它使得数据库能够支持高并发和事务隔离。本文将介绍MySQL中MVCC的基础知识、原理以及实际适用场景。 1. MVCC的基础知识 MVCC是…