一、应用层调用链
流程图如下
1.1 应用层启动拖放
// 组装 数据ClipData,包括卡片信息
final ClipData data = assembleClipData();
//调用系统拖拽
boolean dragResult = dragView.startDragAndDrop(data, builder, null,
View.DRAG_FLAG_GLOBAL | View.DRAG_FLAG_OPAQUE | DRAG_FLAG_CUSTOM_RETURN_ANIMATION | DRAG_FLAG_CUSTOM_CANCEL_ANIMATION);
1.2应用层监听拖拽事件
getDragLayer().setOnDragListener(new View.OnDragListener() {
@Override
public boolean onDrag(View v, DragEvent event) {
}
});
View.dispatchDragEvent 就会将事件传递到这里
二、Framework 层调用链(View → WindowManagerService)
2.1 View.startDragAndDrop() 实现
源码位置: frameworks/base/core/java/android/view/View.java
// View.java
public final boolean startDragAndDrop(ClipData data,
DragShadowBuilder shadowBuilder,
Object myLocalState,
//1. DRAG_FLAG_ACCESSIBILITY_ACTION 表示不需要动画,所以不需要surface int flags) {
if (a11yEnabled && (flags & View.DRAG_FLAG_ACCESSIBILITY_ACTION) != 0) {
IBinder token = mAttachInfo.mSession.performDrag(
mAttachInfo.mWindow, flags, null,
mAttachInfo.mViewRootImpl.getLastTouchSource(),
mAttachInfo.mViewRootImpl.getLastTouchDeviceId(),
mAttachInfo.mViewRootImpl.getLastTouchPointerId(),
0f, 0f, 0f, 0f, data);
}
// 2. 创建DragSurface,大小为view的大小
final SurfaceControl surfaceControl = new SurfaceControl.Builder()
.setName("drag surface")
.setParent(root.getSurfaceControl())
.setBufferSize(shadowSize.x, shadowSize.y)
.setFormat(PixelFormat.TRANSLUCENT)
.setCallsite("View.startDragAndDrop")
.build();
transaction.setMatrix(surfaceControl, 1 / overrideInvScale, 0, 0, 1 / overrideInvScale)
.apply();
final Surface surface = new Surface();
surface.copyFrom(surfaceControl);
//3.创建scanvas
final Canvas canvas = isHardwareAccelerated()
? surface.lockHardwareCanvas()
: surface.lockCanvas(null);
canvas.drawColor(0, PorterDuff.Mode.CLEAR);
//4.绘制内容,最终调用view.draw(canvas)
shadowBuilder.onDrawShadow(canvas);
//5.调用 ViewRootImpl.performDrag()
result = mAttachInfo.mSession.performDrag(mAttachInfo.mWindow, flags, surfaceControl,
root.getLastTouchSource(), root.getLastTouchDeviceId(),
root.getLastTouchPointerId(), lastTouchPoint.x, lastTouchPoint.y,
shadowTouchPoint.x, shadowTouchPoint.y, data)!=null;
mAttachInfo.mDragSurface = surface;
return result;
}
public void onDrawShadow(@NonNull Canvas canvas) {
final View view = mView.get();
if (view != null) {
view.draw(canvas); //绘制内容
} else {
Log.e(View.VIEW_LOG_TAG, "Asked to draw drag shadow but no view");
}
}
2.2 Session.performDrag() 实现
源码位置: frameworks/base/services/core/java/com/android/server/wm/Session.java
@Override
public IBinder performDrag(IWindow window, int flags, SurfaceControl surface, int touchSource,
int touchDeviceId, int touchPointerId, float touchX, float touchY, float thumbCenterX,
float thumbCenterY, ClipData data) {
final int callingUid = Binder.getCallingUid();
final int callingPid = Binder.getCallingPid();
// Validate and resolve ClipDescription data before clearing the calling identity
validateAndResolveDragMimeTypeExtras(data, callingUid, callingPid, mPackageName);
validateDragFlags(flags, callingUid);
final long ident = Binder.clearCallingIdentity();
try {
return mDragDropController.performDrag(mPid, mUid, window, flags, surface, touchSource,
touchDeviceId, touchPointerId, touchX, touchY, thumbCenterX, thumbCenterY,
data);
} finally {
Binder.restoreCallingIdentity(ident);
}
}
2.3 DragDropController .performDrag() 调用
源码位置: frameworks/base/services/core/java/com/android/server/wm/DragDropController.java
// IWindowSession.aidl
IBinder performDrag(int callerPid, int callerUid, IWindow window, int flags,
SurfaceControl surface, int touchSource, int touchDeviceId, int touchPointerId,
float touchX, float touchY, float thumbCenterX, float thumbCenterY, ClipData data) {
//1.初始化DragState
mDragState = new DragState(mService, this, token, surface, flags, winBinder);
surface = null;
mDragState.mPid = callerPid;
mDragState.mUid = callerUid;
mDragState.mOriginalAlpha = alpha;
mDragState.mAnimatedScale = callingWin.mGlobalScale;
mDragState.mToken = dragToken;
mDragState.mDisplayContent = displayContent;
mDragState.mData = data;
mDragState.mCallingTaskIdToHide = shouldMoveCallingTaskToBack(callingWin,
flags);
//2.给InputFlinger注册拖拽标记
touchFocusTransferredFuture = mCallback.get().registerInputChannel(
mDragState, display, mService.mInputManager,
callingWin.mInputChannelToken);
//3.分发第一个拖拽事件到当前窗口,当前窗口需要 设置 PRIVATE_FLAG_INTERCEPT_GLOBAL_DRAG_AND_DROP
mDragState.broadcastDragStartedLocked(touchX, touchY)
//4.调整surface层级,重新绑定parent
displayContent.reparentToOverlay(transaction, surfaceControl);
}
三、系统服务层调用链(WindowManagerService)
3.1 WindowManagerInternal.registerInputChannel()调用
源码位置: frameworks/base/services/core/java/com/android/server/wm/WindowManagerInternal.java
default CompletableFuture<Boolean> registerInputChannel(
DragState state, Display display, InputManagerService service,
IBinder sourceInputChannelToken) {
return state.register(display)
.thenApply(unused ->
service.startDragAndDrop(sourceInputChannelToken, state.getInputToken()));
}
3.2 InputManagerService.startDragAndDrop()调用
源码位置: frameworks/base/services/core/java/com/android/server/input/InputManagerService.java
public boolean startDragAndDrop(@NonNull IBinder fromChannelToken,
@NonNull IBinder dragAndDropChannelToken) {
return mNative.transferTouchGesture(fromChannelToken, dragAndDropChannelToken,
true /* isDragDrop */);
}
3.3 com_android_server_input_InputManagerService. nativeTransferTouchGesture()调用
源码位置: frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp
static jboolean nativeTransferTouchGesture(JNIEnv* env, jobject nativeImplObj,
jobject fromChannelTokenObj, jobject toChannelTokenObj,
jboolean isDragDrop) {
if (fromChannelTokenObj == nullptr || toChannelTokenObj == nullptr) {
return JNI_FALSE;
}
sp<IBinder> fromChannelToken = ibinderForJavaObject(env, fromChannelTokenObj);
sp<IBinder> toChannelToken = ibinderForJavaObject(env, toChannelTokenObj);
NativeInputManager* im = getNativeInputManager(env, nativeImplObj);
if (im->getInputManager()->getDispatcher().transferTouchGesture(fromChannelToken,
toChannelToken, isDragDrop)) {
return JNI_TRUE;
} else {
return JNI_FALSE;
}
}
四、输入系统调用链(InputDispatcher)
4.1InputDispatcher.transferTouchGesture()标记拖拽
源码位置: frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp
bool InputDispatcher::transferTouchGesture(const sp<IBinder>& fromToken, const sp<IBinder>& toToken,
bool isDragDrop) {
...
// Store the dragging window.
if (isDragDrop) {
if (pointers.size() != 1) {
ALOGW("The drag and drop cannot be started when there is no pointer or more than 1"
" pointer on the window.");
return false;
}
// Track the pointer id for drag window and generate the drag state.
const size_t id = pointers.begin()->id;
//1.初始化mDragState
mDragState = std::make_unique<DragState>(toWindowHandle, deviceId, id);
}
//2.唤醒事件分发,进入下一个循环
mLooper->wake();
}
4.2添加拖拽事件到队列
InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, const MotionEntry& entry) {
...
addDragEventLocked(entry)// 添加Drag事件到队列中
...
}
void InputDispatcher::addDragEventLocked(const MotionEntry& entry) {
...
//添加拖拽事件到队列
enqueueDragEventLocked(mDragState->dragHoverWindowHandle, /*isExiting=*/true, x,
y)
....
}
void InputDispatcher::enqueueDragEventLocked(const sp<WindowInfoHandle>& windowHandle,
bool isExiting, const int32_t rawX,
const int32_t rawY) {
const vec2 xy = windowHandle->getInfo()->transform.transform(vec2(rawX, rawY));
//初始化事件
std::unique_ptr<DragEntry> dragEntry =
std::make_unique<DragEntry>(mIdGenerator.nextId(), now(), windowHandle->getToken(),
isExiting, xy.x, xy.y);
//添加拖拽事件到队列
enqueueInboundEventLocked(std::move(dragEntry));
}
4.3 通过socket发送拖拽事件
void InputDispatcher::dispatchOnceInnerLocked(nsecs_t& nextWakeupTime) {
switch (mPendingEvent->type) {
case EventEntry::Type::DRAG: {
std::shared_ptr<const DragEntry> typedEntry =
std::static_pointer_cast<const DragEntry>(mPendingEvent);
dispatchDragLocked(currentTime, typedEntry);
done = true;
break;
}
...
}
}
void InputDispatcher::dispatchDragLocked(nsecs_t currentTime,
std::shared_ptr<const DragEntry> entry) {
std::shared_ptr<Connection> connection =
mConnectionManager.getConnection(entry->connectionToken);
if (connection == nullptr) {
return; // Connection has gone away
}
entry->dispatchInProgress = true;
dispatchEventLocked(currentTime, entry, {{connection}});
}
后续跟事件输入的流程基本一样了,dispatchEventLocked最终到startDispatchCycleLocked
void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
const std::shared_ptr<Connection>& connection) {
switch (eventEntry.type) {
case EventEntry::Type::DRAG: {
const DragEntry& dragEntry = static_cast<const DragEntry&>(eventEntry);
//调用socket发送事件
status = connection->inputPublisher.publishDragEvent(dispatchEntry->seq,
dragEntry.id, dragEntry.x,
dragEntry.y,
dragEntry.isExiting);
break;
}
}
}
后续流程可以参考 Android输入系统源码分析(上)
五、应用层接受事件
5.1InputEventReceiver.consumeEvents接受事件后消费事件
frameworks/base/core/jni/android_view_InputEventReceiver.cpp
status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env,
bool consumeBatches, nsecs_t frameTime, bool* outConsumedBatch) {
InputEvent* inputEvent;
//读取事件
status_t status = mInputConsumer.consume(&mInputEventFactory,
consumeBatches, frameTime, &seq, &inputEvent);
switch (inputEvent->getType()) {
case InputEventType::MOTION: {
env->CallVoidMethod(receiverObj.get(),
gInputEventReceiverClassInfo.dispatchInputEvent, seq,
inputEventObj.get());
}
//拖拽事件处理
case InputEventType::DRAG: {
const DragEvent* dragEvent = static_cast<DragEvent*>(inputEvent);
env->CallVoidMethod(receiverObj.get(), gInputEventReceiverClassInfo.onDragEvent,
jboolean(dragEvent->isExiting()), dragEvent->getX(),
dragEvent->getY());
}
...
}
}
5.2ViewRootImpl$WindowInputEventReceiver.onDragEvent
frameworks/base/core/java/android/view/ViewRootImpl.java
final class WindowInputEventReceiver extends InputEventReceiver {
public void onDragEvent(boolean isExiting, float x, float y) {
// force DRAG_EXITED_EVENT if appropriate
DragEvent event = DragEvent.obtain(
isExiting ? DragEvent.ACTION_DRAG_EXITED : DragEvent.ACTION_DRAG_LOCATION,
x, y, 0 /* offsetX */, 0 /* offsetY */, 0 /* flags */, null/* localState */,
null/* description */, null /* data */, null /* dragSurface */,
null /* dragAndDropPermissions */, false /* result */);
dispatchDragEvent(event);
}
}
dispatchDragEvent后续会调用到 handleDragEvent,然后调用到View.dispatchDragEvent
这样应用层的 通过 setOnDragListener 设置的listener
六、总结
6.1 核心流程
- 应用层启动: 调用
View.startDragAndDrop(DRAG_FLAG_GLOBAL) - Framework 层:
ViewRootImpl.performDrag()通过 Binder 调用系统服务 - 系统服务层:
WindowManagerService.performDrag()创建DragState,通知InputDispatcher - 输入系统:
InputDispatcher将触摸事件转换为拖放事件,分发到所有符合条件的窗口 - 应用层接收: Launcher 通过
IWindow.dispatchDragEvent()
6.2时序图
主要流程时序图
sequenceDiagram
participant App as 应用层
participant View as View/ViewRootImpl
participant WMS as WindowManagerService
participant InputDispatcher as InputDispatcher
participant InputChannel as InputChannel
Note over App,InputChannel: 拖拽启动流程
App->>View: startDragAndDrop(flags=GLOBAL)
View->>View: 创建DragSurface
View->>WMS: Session.performDrag()
WMS->>WMS: DragDropController.performDrag()
WMS->>WMS: 创建DragState
WMS->>InputDispatcher: registerInputChannel()
InputDispatcher->>InputDispatcher: transferTouchGesture()
InputDispatcher->>InputDispatcher: 初始化mDragState
Note over App,InputChannel: 事件分发流程
loop 每次触摸移动
InputDispatcher->>InputDispatcher: 检测触摸事件
InputDispatcher->>InputDispatcher: addDragEventLocked()
InputDispatcher->>InputDispatcher: enqueueDragEventLocked()
InputDispatcher->>InputChannel: publishDragEvent()
InputChannel->>View: 发送拖拽事件
View->>App: dispatchDragEvent()
App->>App: OnDragListener.onDrag()
end
Note over App,InputChannel: 拖拽结束流程
App->>View: 调用endDrag()
View->>WMS: 结束拖拽
WMS->>InputDispatcher: 清理DragState
InputDispatcher->>InputDispatcher: 发送DRAG_EXITED事件
数据流转时序图
sequenceDiagram
participant Launcher as App
participant ClipData as ClipData
participant Surface as DragSurface
participant DragState as DragState
participant DragEntry as DragEntry
participant DragEvent as DragEvent
Note over Launcher,DragEvent: 数据创建和传递流程
Launcher->>ClipData: assembleClipData()<br/>创建ClipData对象<br/>包含卡片信息
Launcher->>Surface: 创建SurfaceControl<br/>绘制拖拽阴影
Launcher->>DragState: performDrag()<br/>传递ClipData和Surface
DragState->>DragState: 保存mData=ClipData<br/>保存mSurface=Surface
Note over Launcher,DragEvent: 事件生成流程
InputDispatcher->>DragEntry: enqueueDragEventLocked()<br/>创建DragEntry<br/>包含x, y, isExiting
DragEntry->>DragEntry: 坐标转换<br/>transform(rawX, rawY)
Note over Launcher,DragEvent: 事件接收流程
InputReceiver->>DragEvent: 解析Socket数据<br/>创建DragEvent对象
DragEvent->>DragEvent: 设置ACTION类型<br/>ACTION_DRAG_LOCATION<br/>或ACTION_DRAG_EXITED
DragEvent->>Launcher: dispatchDragEvent()<br/>传递到应用层
Launcher->>Launcher: 从event.getClipData()<br/>获取原始数据
完整时序图
sequenceDiagram
participant Launcher as App应用层
participant View as View
participant ViewRootImpl as ViewRootImpl
participant Session as Session
participant DragDropController as DragDropController
participant WMS as WindowManagerService
participant InputManager as InputManagerService
participant InputDispatcher as InputDispatcher
participant Socket as Socket通信
participant InputReceiver as InputEventReceiver
participant DragListener as OnDragListener
Note over Launcher,DragListener: 一、启动拖拽阶段
Launcher->>Launcher: assembleClipData<br/>组装卡片数据
Launcher->>View: startDragAndDrop(data, builder, flags)
View->>View: 检查DRAG_FLAG_ACCESSIBILITY_ACTION
alt 无障碍模式
View->>Session: performDrag(无需Surface)
else 正常模式
View->>View: 创建SurfaceControl
View->>View: 创建Canvas并绘制阴影
View->>ViewRootImpl: performDrag(surfaceControl, data)
end
ViewRootImpl->>Session: performDrag(window, flags, surface, data)
Session->>DragDropController: performDrag(...)
Note over DragDropController: 初始化DragState
DragDropController->>DragDropController: 创建DragState对象
DragDropController->>DragDropController: 设置mData, mToken等属性
DragDropController->>WMS: registerInputChannel(DragState)
WMS->>InputManager: startDragAndDrop(sourceToken, dragToken)
InputManager->>InputDispatcher: transferTouchGesture(fromToken, toToken, isDragDrop=true)
Note over InputDispatcher: 初始化拖拽状态
InputDispatcher->>InputDispatcher: 创建mDragState
InputDispatcher->>InputDispatcher: 唤醒事件分发循环
Note over Launcher,DragListener: 二、事件分发阶段
InputDispatcher->>InputDispatcher: findTouchedWindowTargetsLocked
InputDispatcher->>InputDispatcher: addDragEventLocked
InputDispatcher->>InputDispatcher: enqueueDragEventLocked<br/>创建DragEntry
InputDispatcher->>InputDispatcher: enqueueInboundEventLocked<br/>添加到队列
InputDispatcher->>InputDispatcher: dispatchOnceInnerLocked
InputDispatcher->>InputDispatcher: dispatchDragLocked
InputDispatcher->>InputDispatcher: startDispatchCycleLocked
InputDispatcher->>Socket: publishDragEvent(seq, id, x, y, isExiting)
Note over Launcher,DragListener: 三、应用层接收阶段
Socket->>InputReceiver: 接收拖拽事件数据
InputReceiver->>InputReceiver: consumeEvents
InputReceiver->>InputReceiver: InputConsumer.consume<br/>解析DragEvent
InputReceiver->>ViewRootImpl: onDragEvent(isExiting, x, y)
ViewRootImpl->>ViewRootImpl: 创建DragEvent对象<br/>ACTION_DRAG_LOCATION<br/>或ACTION_DRAG_EXITED
ViewRootImpl->>View: dispatchDragEvent(event)
View->>DragListener: onDrag(v, event)
DragListener->>Launcher: handleDragEvent(event)
Note over Launcher: 处理拖拽事件<br/>更新UI状态