android usb相关知识总结

1 篇文章 0 订阅

转载请注明出处:http://blog.csdn.net/droyon/article/details/45098027

1、android背景介绍

UsbService,在系统启动时创建,在该文件中,和usb状态息息相关的操作类是UsbDeviceManager,大部分的usb以及adb相关的逻辑,在这个类中做处理。UsbDeviceManager中,我们需要关注三部分内容。一、配置文件。二、  private final UEventObserver mUEventObserver = new UEventObserver() ,接受UEvent事件。三、UsbHandler。

其中配置文件,保存当前usb状态。UEventObserver接受usb事件,push给UsbHandler来处理。UsbHandler是用来处理Usb事件的关键类。

2、Usb默认状态从哪里获取,当前的默认状态又是什么?

Usb的当前状态保存在mCurrentFunctions成员变量中,该变量在UsbHandler的构造中进行初始化。

mDefaultFunctions = SystemProperties.get("persist.sys.usb.config", "adb");

                // Check if USB mode needs to be overridden depending on OEM specific bootmode.
                mDefaultFunctions = processOemUsbOverride(mDefaultFunctions);

                // sanity check the sys.usb.config system property
                // this may be necessary if we crashed while switching USB configurations
                String config = SystemProperties.get("sys.usb.config", "none");
                if (!config.equals(mDefaultFunctions)) {
                    Slog.w(TAG, "resetting config to persistent property: " + mDefaultFunctions);
                    SystemProperties.set("sys.usb.config", mDefaultFunctions);
                }

                mCurrentFunctions = mDefaultFunctions;

3、插入usb时,弹出adb以及Notification通知的大体流程是什么?

插入usb时,我们的UEventObserver会收到信息,最终push给UsbHandler。

UEvent信息:

04-17 14:20:03.352 V/UsbDeviceManager(  759): USB UEVENT: {USB_STATE=DISCONNECTED, SUBSYSTEM=android_usb, SEQNUM=7528, ACTION=change, DEVPATH=/devices/virtual/android_usb/android0}
然后执行UsbHandler的updateState方法。
private final UEventObserver mUEventObserver = new UEventObserver() {
        @Override
        public void onUEvent(UEventObserver.UEvent event) {
            if (DEBUG) Slog.v(TAG, "USB UEVENT: " + event.toString());

            String state = event.get("USB_STATE");
            String accessory = event.get("ACCESSORY");
            if (state != null) {
                mHandler.updateState(state);
            } else if ("START".equals(accessory)) {
                if (DEBUG) Slog.d(TAG, "got accessory start");
                startAccessoryMode();
            }
        }
    };

updateState方法:更新mConnection状态。

public void updateState(String state) {
            int connected, configured;

            if ("DISCONNECTED".equals(state)) {
                connected = 0;
                configured = 0;
            } else if ("CONNECTED".equals(state)) {
                connected = 1;
                configured = 0;
            } else if ("CONFIGURED".equals(state)) {
                connected = 1;
                configured = 1;
            } else {
                Slog.e(TAG, "unknown state " + state);
                return;
            }
            removeMessages(MSG_UPDATE_STATE);
            Message msg = Message.obtain(this, MSG_UPDATE_STATE);
            msg.arg1 = connected;
            msg.arg2 = configured;
            // debounce disconnects to avoid problems bringing up USB tethering
            sendMessageDelayed(msg, (connected == 0) ? UPDATE_DELAY : 0);
        }
最后在UsbHandler中进行更新状态,进而弹出adb以及usb的Notification

case MSG_UPDATE_STATE:
                    mConnected = (msg.arg1 == 1);
                    mConfigured = (msg.arg2 == 1);
                    updateUsbNotification();
                    updateAdbNotification();
                    if (containsFunction(mCurrentFunctions,
                            UsbManager.USB_FUNCTION_ACCESSORY)) {
                        updateCurrentAccessory();
                    } else if (!mConnected) {
                        // restore defaults when USB is disconnected
                        setEnabledFunctions(mDefaultFunctions, false);
                    }
                    if (mBootCompleted) {
                        updateUsbState();
                        updateAudioSourceFunction();
                    }
                    break;
4、可设置的usb类型有哪些?
public static final String USB_FUNCTION_MASS_STORAGE = "mass_storage";

    /**
     * Name of the adb USB function.
     * Used in extras for the {@link #ACTION_USB_STATE} broadcast
     *
     * {@hide}
     */
    public static final String USB_FUNCTION_ADB = "adb";

    /**
     * Name of the RNDIS ethernet USB function.
     * Used in extras for the {@link #ACTION_USB_STATE} broadcast
     *
     * {@hide}
     */
    public static final String USB_FUNCTION_RNDIS = "rndis";

    /**
     * Name of the MTP USB function.
     * Used in extras for the {@link #ACTION_USB_STATE} broadcast
     *
     * {@hide}
     */
    public static final String USB_FUNCTION_MTP = "mtp";

    /**
     * Name of the PTP USB function.
     * Used in extras for the {@link #ACTION_USB_STATE} broadcast
     *
     * {@hide}
     */
    public static final String USB_FUNCTION_PTP = "ptp";

    /**
     * Name of the CHARGING USB function.
     * Used in extras for the {@link #ACTION_USB_STATE} broadcast
     *
     * {@hide}
     */
    public static final String USB_FUNCTION_CHARGING = "charging";

    /**
     * Name of the audio source USB function.
     * Used in extras for the {@link #ACTION_USB_STATE} broadcast
     *
     * {@hide}
     */
    public static final String USB_FUNCTION_AUDIO_SOURCE = "audio_source";

    /**
     * Name of the Accessory USB function.
     * Used in extras for the {@link #ACTION_USB_STATE} broadcast
     *
     * {@hide}
     */
    public static final String USB_FUNCTION_ACCESSORY = "accessory";

这些是其定义。其中adb与charging不能同时兼容。


ps:Charging在底层是没有设备文件与之对应的,设定充电模式,会将adb等配置移除.


5、设置usb的流程是什么?

上层能够设定usb类型的类名叫做:UsbSettings,在其中,用户可以设定当前UsbSettings状态为mtp、ptp以及厂商定义的其他usb状态。

在用户操作时,会调用mUsbManager.setCurrentFunction(function, true);

tring function = USB_FUNCTION_DEFAULT;
        if (preference == mMtp && mMtp.isChecked()) {
            function = UsbManager.USB_FUNCTION_MTP;
        } else if (preference == mPtp && mPtp.isChecked()) {
            function = UsbManager.USB_FUNCTION_PTP;
        } else if (preference == mCharging && mCharging.isChecked()) {
            function = UsbManager.USB_FUNCTION_CHARGING;
        } else if (preference == mSDCard && mSDCard.isChecked()) {
            function = UsbManager.USB_FUNCTION_MASS_STORAGE;
        }

        operateInprogress = true;
        mUsbManager.setCurrentFunction(function, true);
        updateToggles(function);
USBManager会继而调用UsbService的setCurrentFunction

UsbService.java

@Override
    public void setCurrentFunction(String function, boolean makeDefault) {
        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);

        // If attempt to change USB function while file transfer is restricted, ensure that
        // the current function is set to "none", and return.
        UserManager userManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
        if (userManager.hasUserRestriction(UserManager.DISALLOW_USB_FILE_TRANSFER)) {
            if (mDeviceManager != null) mDeviceManager.setCurrentFunctions("none", false);
            return;
        }

        if (mDeviceManager != null) {
            mDeviceManager.setCurrentFunctions(function, makeDefault);
        } else {
            throw new IllegalStateException("USB device mode not supported");
        }
    }

最终还是会调用UsbDeviceManager中的setCurrentFunction。

UsbDeviceManager.java

public void setCurrentFunctions(String functions, boolean makeDefault) {
        if (DEBUG) Slog.d(TAG, "setCurrentFunctions(" + functions + ") default: " + makeDefault);
        mHandler.sendMessage(MSG_SET_CURRENT_FUNCTIONS, functions, makeDefault);
    }
在内部类UsbHandler中:

case MSG_SET_CURRENT_FUNCTIONS:
                    String functions = (String)msg.obj;
                    boolean makeDefault = (msg.arg1 == 1);
                    setEnabledFunctions(functions, makeDefault);
                    break;
setEnabledFunctions方法中:

private void setEnabledFunctions(String functions, boolean makeDefault) {
            if (DEBUG) Slog.d(TAG, "setEnabledFunctions " + functions
                    + " makeDefault: " + makeDefault);

            // Do not update persystent.sys.usb.config if the device is booted up
            // with OEM specific mode.
            if (functions != null && makeDefault && !needsOemUsbOverride()) {//0,persist.sys.usb.config为usb的默认配置值,makeDefault是说在每次Usb切换时,是否改变默认配置.

                if (!UsbManager.USB_FUNCTION_CHARGING.equals(functions)
                        && mAdbEnabled) {//1,首先UsbManager是否设定为充电模式,如果是,从当前UsbFuncton中移除adb,否则,为当前UsbFunctions增加adb.
                    functions = addFunction(functions, UsbManager.USB_FUNCTION_ADB);
                } else {
                    functions = removeFunction(functions, UsbManager.USB_FUNCTION_ADB);
                }
                if (!mDefaultFunctions.equals(functions)) {//2,如果当前模式与当前默认模式不一致
                    if (!setUsbConfig("none")) {//3,设定sys.usb.config为none[在由一种usb模式切换为另一种usb模式时,需要先将之前的模式设定为none,因为
                                                //init.rc中有如下触发器:on property:persist.sys.usb.config=* setprop sys.usb.config $persist.sys.usb.config]
                        Slog.e(TAG, "Failed to disable USB");
                        // revert to previous configuration if we fail
                        setUsbConfig(mCurrentFunctions);
                        return;
                    }
                    // setting this property will also change the current USB state
                    // via a property trigger
                    SystemProperties.set("persist.sys.usb.config", functions);//4,设定当前usb 功能配置,同时sys.usb.config也会随着改变,因为触发器的原因.
                    if (waitForState(functions)) {
                        mCurrentFunctions = functions;
                        mDefaultFunctions = functions;
                    } else {
                        Slog.e(TAG, "Failed to switch persistent USB config to " + functions);
                        // revert to previous configuration if we fail
                        SystemProperties.set("persist.sys.usb.config", mDefaultFunctions);
                    }
                }
            } else {
                if (functions == null) {
                    functions = mDefaultFunctions;
                }

                // Override with bootmode specific usb mode if needed
                functions = processOemUsbOverride(functions);

                if (!UsbManager.USB_FUNCTION_CHARGING.equals(functions)
                        && mAdbEnabled) {//5,首先UsbManager是否设定为充电模式,如果是,从当前UsbFuncton中移除adb,否则,为当前UsbFunctions增加adb.
                    functions = addFunction(functions, UsbManager.USB_FUNCTION_ADB);
                } else {
                    functions = removeFunction(functions, UsbManager.USB_FUNCTION_ADB);
                }
                if (!mCurrentFunctions.equals(functions)) {//6,当前模式与设定不一致时,设定sys.usb.config,底层会读取该属性,进而启用相应的设备文件节点.
                    if (!setUsbConfig("none")) {
                        Slog.e(TAG, "Failed to disable USB");
                        // revert to previous configuration if we fail
                        setUsbConfig(mCurrentFunctions);
                        return;
                    }
                    if (setUsbConfig(functions)) {
                        mCurrentFunctions = functions;
                    } else {
                        Slog.e(TAG, "Failed to switch USB config to " + functions);
                        // revert to previous configuration if we fail
                        setUsbConfig(mCurrentFunctions);
                    }
                }
            }
        }

总结:
1,在usb链接状态时,sys.usb.config与persist.sys.usb.config由于触发器的原因会保持一致.
2,当Usb状态断开时,sys.usb.config由于与persist.sys.usb.config触发器的原因,本应保持一致,但应移除是否含有adb功能配置.
3,充电模式与adb不可同时共存.


附:log文件:
1,由ptp切换模式至mtp模式log信息:
07-15 20:34:56.862 D/UsbDeviceManager(  761): setEnabledFunctions - functions: mtp
07-15 20:34:56.862 D/UsbDeviceManager(  761): setEnabledFunctions - mDefaultFunctions: ptp,adb
07-15 20:34:56.862 D/UsbDeviceManager(  761): setEnabledFunctions - mCurrentFunctions: ptp,adb
07-15 20:34:56.862 D/UsbDeviceManager(  761): setEnabledFunctions - mSettingFunction: ptp,adb
07-15 20:34:56.862 D/UsbDeviceManager(  761): Add adb into mtp
07-15 20:34:56.862 D/UsbDeviceManager(  761): sys.usb.acm_idx=,mAcmPortIdx=
07-15 20:34:56.867 D/UsbDeviceManager(  761): setEnabledFunctions - functions: mtp,adb
07-15 20:34:56.868 D/UsbDeviceManager(  761): setUsbConfig(none)
07-15 20:34:56.868 D/UsbDeviceManager(  761): setUsbConfig - config: none
07-15 20:34:56.976 D/UsbDeviceManager(  761): handleMessage - MSG_SET_CURRENT_FUNCTION - functions: mtp
07-15 20:34:57.241 V/UsbDeviceManager(  761): USB UEVENT: {USB_STATE=DISCONNECTED, SUBSYSTEM=android_usb, SEQNUM=2751, ACTION=change, DEVPATH=/devices/virtual/android_usb/android0}
07-15 20:34:57.242 D/UsbDeviceManager(  761): mUEventObserver - onUEvent - state: DISCONNECTED
07-15 20:34:57.242 D/UsbDeviceManager(  761): updateState - DISCONNECTED
07-15 20:34:57.242 D/UsbDeviceManager(  761): updateState - RNDIS_UPDATE_DELAY  DISCONNECTED mSettingFunction: mtp
07-15 20:34:57.331 V/UsbDeviceManager(  761): USB UEVENT: {USB_STATE=CONNECTED, SUBSYSTEM=android_usb, SEQNUM=2756, ACTION=change, DEVPATH=/devices/virtual/android_usb/android0}
07-15 20:34:57.331 D/UsbDeviceManager(  761): mUEventObserver - onUEvent - state: CONNECTED
07-15 20:34:57.331 D/UsbDeviceManager(  761): updateState - CONNECTED
07-15 20:34:57.331 D/UsbDeviceManager(  761): updateState - RNDIS_UPDATE_DELAY  CONNECTED mSettingFunction: mtp
07-15 20:34:57.332 W/UsbDeviceManager(  761): handleMessage - 0
07-15 20:34:57.332 D/UsbDeviceManager(  761): updateUsbNotification - mNotificationManager: android.app.NotificationManager@230489b9
07-15 20:34:57.332 D/UsbDeviceManager(  761): updateUsbNotification - mUseUsbNotification: true
07-15 20:34:57.332 W/UsbDeviceManager(  761): updateUsbNotification - mConnected: true
07-15 20:34:57.332 W/UsbDeviceManager(  761): updateUsbNotification - mCurrentFunctions: mtp,adb
07-15 20:34:57.332 D/UsbDeviceManager(  761): updateUsbNotification - containsFunction:  USB_FUNCTION_MTP
07-15 20:34:57.332 D/UsbDeviceManager(  761): UsbDeviceManager updateUsbNotification mConnected is:true,mBootCompleted is:true,mUsbNotificationId is:17040616,id is:17040615,mCurrentFunctions is:mtp,adb,mDefaultFunctions is:mtp,adb
07-15 20:34:57.334 V/UsbDeviceManager(  761): USB UEVENT: {USB_STATE=CONFIGURED, SUBSYSTEM=android_usb, SEQNUM=2757, ACTION=change, DEVPATH=/devices/virtual/android_usb/android0}
07-15 20:34:57.334 D/UsbDeviceManager(  761): mUEventObserver - onUEvent - state: CONFIGURED
07-15 20:34:57.334 D/UsbDeviceManager(  761): updateState - CONFIGURED
07-15 20:34:57.334 D/UsbDeviceManager(  761): updateState - RNDIS_UPDATE_DELAY  CONFIGURED mSettingFunction: mtp
07-15 20:34:57.340 D/UsbDeviceManager(  761): UsbDeviceManager updateUsbNotification mConnected is:true,mBootCompleted is:true,show is:true,setupWized is:true,isInCall is:false
07-15 20:34:57.342 D/UsbDeviceManager(  761): broadcasting Intent { act=android.hardware.usb.action.USB_STATE flg=0x20000000 (has extras) } connected: true configured: false
07-15 20:34:57.347 W/UsbDeviceManager(  761): sys.usb.mtpConnect = mtpConnection
07-15 20:34:57.347 D/UsbDeviceManager(  761): sys.usb.acm_idx=
07-15 20:34:57.347 D/UsbDeviceManager(  761): handleMessage mConnected:true,mConfigured:false, mHwDisconnected:false
07-15 20:34:57.347 W/UsbDeviceManager(  761): handleMessage - 0
07-15 20:34:57.347 D/UsbDeviceManager(  761): updateUsbNotification - mNotificationManager: android.app.NotificationManager@230489b9
07-15 20:34:57.347 D/UsbDeviceManager(  761): updateUsbNotification - mUseUsbNotification: true
07-15 20:34:57.347 W/UsbDeviceManager(  761): updateUsbNotification - mConnected: true
07-15 20:34:57.347 W/UsbDeviceManager(  761): updateUsbNotification - mCurrentFunctions: mtp,adb
07-15 20:34:57.347 D/UsbDeviceManager(  761): updateUsbNotification - containsFunction:  USB_FUNCTION_MTP
07-15 20:34:57.347 D/UsbDeviceManager(  761): UsbDeviceManager updateUsbNotification mConnected is:true,mBootCompleted is:true,mUsbNotificationId is:17040615,id is:17040615,mCurrentFunctions is:mtp,adb,mDefaultFunctions is:mtp,adb
07-15 20:34:57.348 D/UsbDeviceManager(  761): broadcasting Intent { act=android.hardware.usb.action.USB_STATE flg=0x20000000 (has extras) } connected: true configured: true
07-15 20:34:57.381 W/UsbDeviceManager(  761): sys.usb.mtpConnect = mtpConnection
07-15 20:34:57.381 D/UsbDeviceManager(  761): sys.usb.acm_idx=
07-15 20:34:57.381 D/UsbDeviceManager(  761): handleMessage mConnected:true,mConfigured:true, mHwDisconnected:false
2,由ptp切换为仅充电模式:
07-15 21:18:34.226 D/UsbDeviceManager(  753): setEnabledFunctions - functions: charging
07-15 21:18:34.226 D/UsbDeviceManager(  753): setEnabledFunctions - mDefaultFunctions: ptp,adb
07-15 21:18:34.226 D/UsbDeviceManager(  753): setEnabledFunctions - mCurrentFunctions: adb
07-15 21:18:34.226 D/UsbDeviceManager(  753): setEnabledFunctions - mSettingFunction: ptp
07-15 21:18:34.226 D/UsbDeviceManager(  753): sys.usb.acm_idx=,mAcmPortIdx=
07-15 21:18:34.232 D/UsbDeviceManager(  753): setEnabledFunctions - functions: charging
07-15 21:18:34.232 D/UsbDeviceManager(  753): setUsbConfig(none)
07-15 21:18:34.232 D/UsbDeviceManager(  753): setUsbConfig - config: none
07-15 21:18:48.838 D/UsbDeviceManager(  753): handleMessage - MSG_SET_CURRENT_FUNCTION - functions: ptp
07-15 21:18:49.344 D/UsbDeviceManager(  753): onReceive - BATTERY_CHANGED - mPlugType: 2, mSettingUsbCharging: false, mConnected: false, mSettingUsbBicr: false
07-15 21:18:49.425 V/UsbDeviceManager(  753): USB UEVENT: {USB_STATE=CONNECTED, SUBSYSTEM=android_usb, SEQNUM=2327, ACTION=change, DEVPATH=/devices/virtual/android_usb/android0}
07-15 21:18:49.426 D/UsbDeviceManager(  753): mUEventObserver - onUEvent - state: CONNECTED
07-15 21:18:49.426 D/UsbDeviceManager(  753): updateState - CONNECTED
07-15 21:18:49.426 D/UsbDeviceManager(  753): updateState - RNDIS_UPDATE_DELAY  CONNECTED mSettingFunction: ptp
07-15 21:18:49.427 W/UsbDeviceManager(  753): handleMessage - 0
07-15 21:18:49.427 D/UsbDeviceManager(  753): updateUsbNotification - mNotificationManager: android.app.NotificationManager@2f18b8c
07-15 21:18:49.427 D/UsbDeviceManager(  753): updateUsbNotification - mUseUsbNotification: true
07-15 21:18:49.427 W/UsbDeviceManager(  753): updateUsbNotification - mConnected: true
07-15 21:18:49.428 W/UsbDeviceManager(  753): updateUsbNotification - mCurrentFunctions: ptp,adb
07-15 21:18:49.428 D/UsbDeviceManager(  753): updateUsbNotification - containsFunction:  USB_FUNCTION_PTP
07-15 21:18:49.428 D/UsbDeviceManager(  753): UsbDeviceManager updateUsbNotification mConnected is:true,mBootCompleted is:true,mUsbNotificationId is:134545580,id is:17040616,mCurrentFunctions is:ptp,adb,mDefaultFunctions is:ptp,adb
07-15 21:18:49.435 V/UsbDeviceManager(  753): USB UEVENT: {USB_STATE=CONFIGURED, SUBSYSTEM=android_usb, SEQNUM=2328, ACTION=change, DEVPATH=/devices/virtual/android_usb/android0}
07-15 21:18:49.436 D/UsbDeviceManager(  753): mUEventObserver - onUEvent - state: CONFIGURED
07-15 21:18:49.436 D/UsbDeviceManager(  753): updateState - CONFIGURED
07-15 21:18:49.436 D/UsbDeviceManager(  753): updateState - RNDIS_UPDATE_DELAY  CONFIGURED mSettingFunction: ptp
07-15 21:18:49.449 D/UsbDeviceManager(  753): UsbDeviceManager updateUsbNotification mConnected is:true,mBootCompleted is:true,show is:true,setupWized is:true,isInCall is:false
07-15 21:18:49.453 D/UsbDeviceManager(  753): broadcasting Intent { act=android.hardware.usb.action.USB_STATE flg=0x20000000 (has extras) } connected: true configured: false
07-15 21:18:49.486 D/UsbDeviceManager(  753): onReceive - BATTERY_CHANGED - mPlugType: 2, mSettingUsbCharging: false, mConnected: true, mSettingUsbBicr: false
07-15 21:18:49.495 W/UsbDeviceManager(  753): sys.usb.mtpConnect = ptpConnection
07-15 21:18:49.496 D/UsbDeviceManager(  753): sys.usb.acm_idx=
07-15 21:18:49.496 D/UsbDeviceManager(  753): handleMessage mConnected:true,mConfigured:false, mHwDisconnected:false
07-15 21:18:49.497 W/UsbDeviceManager(  753): handleMessage - 0
07-15 21:18:49.498 D/UsbDeviceManager(  753): updateUsbNotification - mNotificationManager: android.app.NotificationManager@2f18b8c
07-15 21:18:49.498 D/UsbDeviceManager(  753): updateUsbNotification - mUseUsbNotification: true
07-15 21:18:49.498 W/UsbDeviceManager(  753): updateUsbNotification - mConnected: true
07-15 21:18:49.498 W/UsbDeviceManager(  753): updateUsbNotification - mCurrentFunctions: ptp,adb
07-15 21:18:49.498 D/UsbDeviceManager(  753): updateUsbNotification - containsFunction:  USB_FUNCTION_PTP
07-15 21:18:49.498 D/UsbDeviceManager(  753): UsbDeviceManager updateUsbNotification mConnected is:true,mBootCompleted is:true,mUsbNotificationId is:17040616,id is:17040616,mCurrentFunctions is:ptp,adb,mDefaultFunctions is:ptp,adb
07-15 21:18:49.499 D/UsbDeviceManager(  753): broadcasting Intent { act=android.hardware.usb.action.USB_STATE flg=0x20000000 (has extras) } connected: true configured: true
07-15 21:18:49.513 W/UsbDeviceManager(  753): sys.usb.mtpConnect = ptpConnection
07-15 21:18:49.513 D/UsbDeviceManager(  753): sys.usb.acm_idx=
07-15 21:18:49.513 D/UsbDeviceManager(  753): handleMessage mConnected:true,mConfigured:true, mHwDisconnected:false





  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hailushijie

您的鼓励是我创作最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值