Android USB默认连接模式为MTP

很多时候,手机项目开发,客户都要求配置USB的默认连接方式,但是在Android 6.0以及之后的版本就直接配置USB连接模式,看到的USB连接模式还是仅充电,而这是google的默认设计。那么对于这个问题,也看了很多网上的一些解法,如:Android 5.0可以直接配置默认值,6.0就不可行了。另外,还有在USB连接的时候进行设置,当连接之后就执行一次设置USB连接模式,将MTP设置为当前连接模式,这样的做法在7.0上面也是可以的。

事实上,当仅充电的时候,查看当前USB模式的配置,就算是mtp,但是还是没有显示SD卡和内部存储器,主要是一个标志的问题。

现有的一种解法

那么这里先说一下在连接USB的情况下,执行一次USB连接模式的设置,这里有一位大牛的方法,并且提到Android 6.0以前的做法,Android 6.0 USB连接模式默认选为MTP ,大家去参考学习一下,那么我说一下这位大牛的改法,在Android 6.0和7.0上面修改后不同的一个地方:

Android版本 在锁屏的情况下 在解锁的情况下
6.0 仅充电 MTP
7.0 MTP MTP

对于这样的解法,我们的测试就提了一个不安全的bug,没有解锁就能直接访问SD卡、内部存储器的数据,这是不安全的。那好像也说得有道理,那么就改。但是这个不解锁能访问存储器的功能,可能又符合某些公司的客户需求。

公司中6.0的解法

对于上面的解法不怎么像6.0的行为,接着我就去看了一下,我们公司以前Android 6.0是怎么修改的,是直接修改了值,将这个值修改后,就能显示SD卡、内部存储器了。

修改文件frameworks/base/services/usb/java/com/android/server/usb/UsbDeviceManager.java

public class UsbDeviceManager {
                  ···省略很多代码···
        private boolean mConfigured;
        //modified in 2017-05-22 start
        //解锁数据,连接电脑,就能看到默认连接模式为MTP
        private boolean mUsbDataUnlocked = true;
        //modified in 2017-05-22 end
        private String mCurrentFunctions;
        private String mDefaultFunctions;
        
                ······
                
         @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MSG_UPDATE_STATE:
                    mConnected = (msg.arg1 == 1);
                    mConfigured = (msg.arg2 == 1);
                    mUsbConfigured = mConfigured;
                    if (!mConnected) {
                        //modified in 2017-05-22 start
                        //default usb connect mode as mtp
                        // When a disconnect occurs, relock access to sensitive user data
                        //断开连接的时候,保持当前连接模式,下次连接的时候还是MTP
                        mUsbDataUnlocked = true;
                        //modified in 2017-05-22 end
                    }
                    updateUsbNotification();
                    updateAdbNotification();
                    if (UsbManager.containsFunction(mCurrentFunctions,
                            UsbManager.USB_FUNCTION_ACCESSORY)) {
                        updateCurrentAccessory();
                    } else if (!mConnected) {
                        //modified  in 2017-05-22 start
                        //change default usb connect mode as mtp,do not restore
                        // 这里不恢复默认连接方式,保持保持当前的连接模式
                        setEnabledFunctions(null, true);
                        //modified  in 2017-05-22 end
                    }
                    if (mBootCompleted) {
                        updateUsbStateBroadcastIfNeeded();
                        updateUsbFunctions();
                    }
                      ······
    }

上面的这种修改方式比较简单,在android6.0和7.0上都是可以的,但是还是有差异:

Android版本 在锁屏的情况下 在解锁的情况下
6.0 仅充电 MTP
7.0 MTP MTP

这中修改方式的最终结果还是跟上面那位大牛的修改方式表现结果一致。那么应该说是Google在7.0上又修改了这一部分的代码,使用公司以前6.0的改法,还是不行。

现在Android 7.0的解法

但是还是对不上公司测试提的问题,那还是需要接续修改。那就仔细看看这类,再上网了解一下USB连接模式这块,这一块还是很深的...,涉及硬件的,都是稍微复杂一点,还要跟底层通信什么的,有一点大概的了解之后,再回来解决一下这个问题,那么从切换USB连接模式的上层实现,那么就是修改mUsbDataUnlocked的值,应该说是在适当的时候修改mUsbDataUnlocked的值,那就看到USB连接模式是MTP,那么下面分析一下有几种情况需要改变:

  1. 手机是锁屏情况下连接USB,连接模式是仅充电。
  2. 手机是解锁的情况下连接USB,连接模式是MTP。
  3. 手机熄屏的情况下断开USB,连接方式要更新为仅充电。
  4. 手机解锁的情况下断开USB,连接方式要更新为仅充电。

应该就是这四种情况,那么下面主要要解决的问题是:

  1. 用户解锁了,通过主测广播:Intent.ACTION_USER_PRESENT判断是否解锁后用户到前台。
  2. USB连接状态有对应的回调,并且这个时候更新USB连接模式。
  3. 熄屏了,通过注册广播Intent.ACTION_SCREEN_OFF判断,还需要注册广播Intent.ACTION_SCREEN_ON,作为屏幕状态值的切换。

在UsbService.java类中注册以上说到的广播接收者,再对UsbDeviceManager.java类中的标识进行更新。

1.修改frameworks/base/services/usb/java/com/android/server/usb/UsbService.java

public class UsbService extends IUsbManager.Stub {
                ······
        final IntentFilter filter = new IntentFilter();
        filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
        filter.addAction(Intent.ACTION_USER_SWITCHED);
        filter.addAction(Intent.ACTION_USER_STOPPED);
        //add by xx in 2017-06-12 for bug 169853 start
        //注册三个广播
        filter.addAction(Intent.ACTION_USER_PRESENT);
        filter.addAction(Intent.ACTION_SCREEN_OFF);
        filter.addAction(Intent.ACTION_SCREEN_ON);
        //add by xx in 2017-06-12 for bug 169853 end
        filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
        mContext.registerReceiver(mReceiver, filter, null, null);
        
                ······

    private BroadcastReceiver mReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
            final String action = intent.getAction();
            if (Intent.ACTION_USER_SWITCHED.equals(action)) {
                setCurrentUser(userId);
            } else if (Intent.ACTION_USER_STOPPED.equals(action)) {
                synchronized (mLock) {
                    mSettingsByUser.remove(userId);
                }
            } else if (DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED
                    .equals(action)) {
                if (mDeviceManager != null) {
                    mDeviceManager.updateUserRestrictions();
                }
            //add by xx in 2017-06-12 for bug 169853 start
            //处理三个广播
            }else if (Intent.ACTION_USER_PRESENT.equals(action)) {

                if (mDeviceManager != null) {
                    mDeviceManager.usbDataUnlocked(true);//这个方法系统有的
                    mDeviceManager.setUserPresent();//这个方法是添加的
                }
            } else if (Intent.ACTION_SCREEN_OFF.equals(action)) {
                if (mDeviceManager != null) {
                    mDeviceManager.updateScreentSate(true);//这个方法是添加的,为了更新屏幕状态
                }
            } else if (Intent.ACTION_SCREEN_ON.equals(action)) {
              if (mDeviceManager != null) {
                    mDeviceManager.updateScreentSate(false);//这个方法是添加的,为了更新屏幕状态
                }
            //add by xx in 2017-06-12 for bug 169853 end
            }
        }
    };
}

2.接下来修改frameworks/base/services/usb/java/com/android/server/usb/UsbDeviceManager.java

public class UsbDeviceManager {
        ·····
    //添加两个全局变量,作为标识
    //modified by xx in 2017-06-12 for bug 169853 start
    private boolean mUserPresent = false;//用户是否结果到前台
    private boolean screenOff = false;//屏幕是否是熄屏
    private boolean changeByUser = false;//切换USB模式的时候,是这里代码切换的,还是用户点击切换的。
    //modified by xx in 2017-06-12 for bug 169853 end
    
            ·····
    //添加这两个方法,在UsbService.java中用到,更新这边的状态
    //modified by xx in 2017-06-12 for bug 169853 start
    public void setUserPresent(){
        mUserPresent = true;
    }

    public void updateScreentSate(boolean state){
        screenOff = state;
        if(!screenOff) {
             mUserPresent = false;
        }
        if(mHandler != null){
            mHandler.updateUsbMode();
        }
    }

    public void usbDataUnlocked(){
        changeByUser  = false;
        mHandler.sendMessage(MSG_SET_USB_DATA_UNLOCKED, true);
    }
    //modified by xx in 2017-06-12 for bug 169853 end
    
            ·····
      
      //更新USB连接状态
      public void updateState(String state) {
            int connected, configured;

            if ("HWDISCONNECTED".equals(state)) {
                connected = 0;
                configured = 0;
                mHwDisconnected = true;
                //add by xx in 2017-08-03 for swtich usb mode start
                changeByUser = false;
                //add by xx in 2017-08-03 for swtich usb mode end
            } else if ("DISCONNECTED".equals(state)) {
                connected = 0;
                configured = 0;
                mHwDisconnected = false;

                //modified by xx in 2017-06-12 for bug 169853 start
                //当熄屏的情况下,更新用户不在前台的标识
                if(screenOff){
                    mUserPresent = false;
                 }
                 //modified by xxx in 2017-06-12 for bug 169853 end

            } else if ("CONNECTED".equals(state)) {
                connected = 1;
                configured = 0;
                
                    ·····
        
        
        private final class UsbHandler extends Handler { 
        
                        ·····
                        
        //在收到更新USB状态的消息之后,更新USB模式,当然要根据用户是否在前台进行判断
         @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MSG_UPDATE_STATE:
                    mConnected = (msg.arg1 == 1);
                    mConfigured = (msg.arg2 == 1);
                    mUsbConfigured = mConfigured;
                    //modified by xx in 2017-06-12 for bug 169853 start
                    //update usb state first
                    updateUsbMode();
                    if (mUserPresent && !changeByUser) {   //用户在前台的
                        mUsbDataUnlocked = true;//解锁数据,那么连接电脑就能看到连接模式为MTP了
                    }
                    //modified by xx in 2017-06-12 for bug 169853 end

                    if (!mConnected) {
                        // When a disconnect occurs, relock access to sensitive user data
                        mUsbDataUnlocked = false;
                    }
                    updateUsbNotification();
                    updateAdbNotification();
                    if (UsbManager.containsFunction(mCurrentFunctions,
                            UsbManager.USB_FUNCTION_ACCESSORY)) {
                        updateCurrentAccessory();
                    } else if (!mConnected) {
                    }
                            ·····//省略代码
                case MSG_SET_USB_DATA_UNLOCKED:
                    //add by xx in 2017-08-03 for swtich usb mode start
                    if(!changeByUser && mUsbDataUnlocked) return;
                    //add by xx in 2017-08-03 for swtich usb mode end
                    setUsbDataUnlocked(msg.arg1 == 1);
                    break;
                }
                            ·····
            //在UsbHandler类中的方法,主要是因为用到USB状态值:mConnected
            //add by xx in 2017-06-12 for bug 169853 start
            private void updateUsbMode(){
                if(!mConnected && screenOff){
                    mUserPresent = false;
                }
            }
            //add by xx in 2017-06-12 for bug 169853 end
        }
                ·····
   }
   //省略其他代码
   public void setCurrentFunctions(String functions) {
        if (DEBUG) Slog.d(TAG, "setCurrentFunctions(" + functions + ")");
        //add by xx in 2017-08-03 for swtich usb mode start
        changeByUser = true;
        //add by xx in 2017-08-03 for swtich usb mode end
        mHandler.sendMessage(MSG_SET_CURRENT_FUNCTIONS, functions);
    }
    //省略其他代码
}

主要修改上面两个类,实现以下情况:

Android版本 在锁屏的情况下 在解锁的情况下
7.0 仅充电 MTP

那么这样的行为就跟Android 6.0 的表现一样了,问题可以说已经解决了。
像这些修改一个默认值的问题还是比较简单的。事实上,对USB完全没有接触,还是要多看,有那么多巨人,就借个肩膀来站站呗,就像本文一开始提到的那位大神一样,在这里表示感谢。

感谢 SymphonyZhang 的提醒,在Android 7.1中“只要persist.sys.usb.config这个属性的值设为mtp,后面不要加上adb那些什么的,就可以了”

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,835评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,598评论 1 295
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,569评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,159评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,533评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,710评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,923评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,674评论 0 203
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,421评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,622评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,115评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,428评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,114评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,097评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,875评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,753评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,649评论 2 271

推荐阅读更多精彩内容