1 /* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.mtp; 18 19 import com.android.internal.util.Preconditions; 20 21 import android.content.Context; 22 import android.content.SharedPreferences; 23 import android.util.ByteStringUtils; 24 25 import java.io.FileDescriptor; 26 import java.util.Random; 27 28 /** 29 * Java wrapper for MTP/PTP support as USB responder. 30 * {@hide} 31 */ 32 public class MtpServer implements Runnable { 33 34 private long mNativeContext; // accessed by native methods 35 private final MtpDatabase mDatabase; 36 private final Runnable mOnTerminate; 37 private final Context mContext; 38 39 // It requires "exactly 32 characters, including any leading 0s" in MTP spec 40 // (5.1.1.14 Serial Number) 41 private static final int sID_LEN_BYTES = 16; 42 private static final int sID_LEN_STR = (sID_LEN_BYTES * 2); 43 44 static { 45 System.loadLibrary("media_jni"); 46 } 47 MtpServer( MtpDatabase database, FileDescriptor controlFd, boolean usePtp, Runnable onTerminate, String deviceInfoManufacturer, String deviceInfoModel, String deviceInfoDeviceVersion)48 public MtpServer( 49 MtpDatabase database, 50 FileDescriptor controlFd, 51 boolean usePtp, 52 Runnable onTerminate, 53 String deviceInfoManufacturer, 54 String deviceInfoModel, 55 String deviceInfoDeviceVersion) { 56 mDatabase = Preconditions.checkNotNull(database); 57 mOnTerminate = Preconditions.checkNotNull(onTerminate); 58 mContext = mDatabase.getContext(); 59 60 final String strID_PREFS_NAME = "mtp-cfg"; 61 final String strID_PREFS_KEY = "mtp-id"; 62 String strRandomId = null; 63 String deviceInfoSerialNumber; 64 65 SharedPreferences sharedPref = 66 mContext.getSharedPreferences(strID_PREFS_NAME, Context.MODE_PRIVATE); 67 if (sharedPref.contains(strID_PREFS_KEY)) { 68 strRandomId = sharedPref.getString(strID_PREFS_KEY, null); 69 70 // Check for format consistence (regenerate upon corruption) 71 if (strRandomId.length() != sID_LEN_STR) { 72 strRandomId = null; 73 } else { 74 // Only accept hex digit 75 for (int ii = 0; ii < strRandomId.length(); ii++) 76 if (Character.digit(strRandomId.charAt(ii), 16) == -1) { 77 strRandomId = null; 78 break; 79 } 80 } 81 } 82 83 if (strRandomId == null) { 84 strRandomId = getRandId(); 85 sharedPref.edit().putString(strID_PREFS_KEY, strRandomId).apply(); 86 } 87 88 deviceInfoSerialNumber = strRandomId; 89 90 native_setup( 91 database, 92 controlFd, 93 usePtp, 94 deviceInfoManufacturer, 95 deviceInfoModel, 96 deviceInfoDeviceVersion, 97 deviceInfoSerialNumber); 98 database.setServer(this); 99 } 100 getRandId()101 private String getRandId() { 102 Random randomVal = new Random(); 103 byte[] randomBytes = new byte[sID_LEN_BYTES]; 104 105 randomVal.nextBytes(randomBytes); 106 return ByteStringUtils.toHexString(randomBytes); 107 } 108 start()109 public void start() { 110 Thread thread = new Thread(this, "MtpServer"); 111 thread.start(); 112 } 113 114 @Override run()115 public void run() { 116 native_run(); 117 native_cleanup(); 118 mDatabase.close(); 119 mOnTerminate.run(); 120 } 121 sendObjectAdded(int handle)122 public void sendObjectAdded(int handle) { 123 native_send_object_added(handle); 124 } 125 sendObjectRemoved(int handle)126 public void sendObjectRemoved(int handle) { 127 native_send_object_removed(handle); 128 } 129 sendObjectInfoChanged(int handle)130 public void sendObjectInfoChanged(int handle) { 131 native_send_object_info_changed(handle); 132 } 133 sendDevicePropertyChanged(int property)134 public void sendDevicePropertyChanged(int property) { 135 native_send_device_property_changed(property); 136 } 137 addStorage(MtpStorage storage)138 public void addStorage(MtpStorage storage) { 139 native_add_storage(storage); 140 } 141 removeStorage(MtpStorage storage)142 public void removeStorage(MtpStorage storage) { 143 native_remove_storage(storage.getStorageId()); 144 } 145 configure(boolean usePtp)146 public static void configure(boolean usePtp) { 147 native_configure(usePtp); 148 } 149 native_configure(boolean usePtp)150 public static native final void native_configure(boolean usePtp); native_setup( MtpDatabase database, FileDescriptor controlFd, boolean usePtp, String deviceInfoManufacturer, String deviceInfoModel, String deviceInfoDeviceVersion, String deviceInfoSerialNumber)151 private native final void native_setup( 152 MtpDatabase database, 153 FileDescriptor controlFd, 154 boolean usePtp, 155 String deviceInfoManufacturer, 156 String deviceInfoModel, 157 String deviceInfoDeviceVersion, 158 String deviceInfoSerialNumber); native_run()159 private native final void native_run(); native_cleanup()160 private native final void native_cleanup(); native_send_object_added(int handle)161 private native final void native_send_object_added(int handle); native_send_object_removed(int handle)162 private native final void native_send_object_removed(int handle); native_send_object_info_changed(int handle)163 private native final void native_send_object_info_changed(int handle); native_send_device_property_changed(int property)164 private native final void native_send_device_property_changed(int property); native_add_storage(MtpStorage storage)165 private native final void native_add_storage(MtpStorage storage); native_remove_storage(int storageId)166 private native final void native_remove_storage(int storageId); 167 } 168