Android MTP之服务端UsbService启动分析了mtp服务端的启动,Android MTP模式切换分析分析了mtp的切换,并且在成功切换后,会发送一个usb状态改变的广播,系统接收这个广播来实现手机存储到pc端的映射.简单来说,通过mtp,pc端能看到手机存储的内容.
接收usb状态改变广播的是MtpReceiver
,它属于packages/providers/MediaProvider
模块,它会调用handleUsbState()
方法处理usb状态改变
// packages/providers/MediaProvider/src/com/android/providers/media/MtpReceiver.java
private void handleUsbState(Context context, Intent intent) {
Bundle extras = intent.getExtras();
boolean configured = extras.getBoolean(UsbManager.USB_CONFIGURED);
boolean connected = extras.getBoolean(UsbManager.USB_CONNECTED);
boolean mtpEnabled = extras.getBoolean(UsbManager.USB_FUNCTION_MTP);
boolean ptpEnabled = extras.getBoolean(UsbManager.USB_FUNCTION_PTP);
boolean unlocked = extras.getBoolean(UsbManager.USB_DATA_UNLOCKED);
boolean isCurrentUser = UserHandle.myUserId() == ActivityManager.getCurrentUser();
if (configured && (mtpEnabled || ptpEnabled)) {
if (!isCurrentUser)
return;
intent = new Intent(context, MtpService.class);
intent.putExtra(UsbManager.USB_DATA_UNLOCKED, unlocked);
if (ptpEnabled) {
intent.putExtra(UsbManager.USB_FUNCTION_PTP, true);
}
context.startService(intent);
} else if (!connected || !(mtpEnabled || ptpEnabled)) {
boolean status = context.stopService(new Intent(context, MtpService.class));
}
}
很简单,usb连接上就启动MtpService
,断开连接就停止它.而启动MtpService
就是为了把存储映射到PC端
// packages/providers/MediaProvider/src/com/android/providers/media/MtpService.java
public synchronized int onStartCommand(Intent intent, int flags, int startId) {
// ...
// 获取主存储
final StorageVolume primary = StorageManager.getPrimaryVolume(mVolumes);
// 映射主存储
// 注意: 第二个参数subdirs是针对ptp模式,而对于mtp模式,值为null
startServer(primary, subdirs);
return START_REDELIVER_INTENT;
}
private synchronized void startServer(StorageVolume primary, String[] subdirs) {
// ...
synchronized (MtpService.class) {
// ...
// 1. 建立上层与JNI层的关系.
// MtpDatabase是MTP操作的上层接口
final MtpDatabase database = new MtpDatabase(this, subdirs);
// MtpServer是JNI和上层交互的接口
final MtpServer server =
new MtpServer(database, fd, mPtpMode,
new OnServerTerminated(), Build.MANUFACTURER,
Build.MODEL, "1.0");
database.setServer(server);
sServerHolder = new ServerHolder(server, database);
// Add currently mounted and enabled storages to the server
// 从这里可以看出,只有数据解锁了,才会映射存储到PC
if (mUnlocked) {
if (mPtpMode) {
} else {
// 2. 通知PC端开始映射存储
// MtpStorage->MtpServer->底层MtpServer->发送Event给pc
for (StorageVolume v : mVolumeMap.values()) {
addStorage(v);
}
}
}
// 3.开启线程,处理PC端请求
server.start();
}
}
映射主存储到pc端,分为三步
MtpDatabase
, MtpServer
对象的时候完成的.addStorage()
通知pc端来添加存储.这是通过向pc端发送mtp event来完成的.
MtpDatabase
类是上层mtp操作的接口,它使用MtpStorageManager
来完成文件系统的操作,使用MediaProvider
来获取音频数据,并且文件操作会同步到MediaProvider
.
MtpServer
类是上层与JNI层交互的接口,MtpDatabase
正是通过MtpServer
实现对底层的操作.
建立上层与JNI层的映射关系,是在MtpDatabase
, MtpServer
的构造函数中完成,本文略过,如果你有jni基础,这段代码非常简单.
首先看下如何通知pc端添加存储,这是通过addStorage()
实现的
// packages/providers/MediaProvider/src/com/android/providers/media/MtpService.java
private void addStorage(StorageVolume volume) {
synchronized (MtpService.class) {
if (sServerHolder != null) {
// 使用MtpDatabase这个上层的MTP操作接口
sServerHolder.database.addStorage(volume);
}
}
}
正如前面所说,MtpDatabase
是上层mtp操作接口,通知pc的任务,肯定必须先经过它
// frameworks/base/media/java/android/mtp/MtpDatabase.java
public void addStorage(StorageVolume storage) {
// MtpStorageManager保存这个存储
MtpStorage mtpStorage = mManager.addMtpStorage(storage);
mStorageMap.put(storage.getPath(), mtpStorage);
// 通过MtpServer,通知JNI层
if (mServer != null) {
mServer.addStorage(mtpStorage);
}
}
正如前面所说,MtpServer
是上层与jni交互的接口,MtpDatabase
内部通过它来打通jni层,通知pc
// frameworks/base/media/java/android/mtp/MtpServer.java
public void addStorage(MtpStorage storage) {
native_add_storage(storage);
}
native_add_storage()
是在JNI层实现的,实现类为android_mtp_MtpServer.cpp
mtp的framework层是在frameworks/base/media/java
mtp的jni层是在frameworks/base/media/jni
支持mtp的jni层的实现在frameworks/av/media/mtp
// frameworks/base/media/jni/android_mtp_MtpServer.cpp
static void
android_mtp_MtpServer_add_storage(JNIEnv *env, jobject thiz, jobject jstorage)
{
Mutex::Autolock autoLock(sMutex);
MtpServer* server = getMtpServer(env, thiz);
if (server) {
// 获取应用层MtpStorage对象的各种属性
jint storageID = env->GetIntField(jstorage, field_MtpStorage_storageId);
jstring path = (jstring)env->GetObjectField(jstorage, field_MtpStorage_path);
jstring description = (jstring)env->GetObjectField(jstorage, field_MtpStorage_description);
jboolean removable = env->GetBooleanField(jstorage, field_MtpStorage_removable);
jlong maxFileSize = env->GetLongField(jstorage, field_MtpStorage_maxFileSize);
const char *pathStr = env->GetStringUTFChars(path, NULL);
if (pathStr != NULL) {
const char *descriptionStr = env->GetStringUTFChars(description, NULL);
if (descriptionStr != NULL) {
// 创建底层的MtpStorage对象
MtpStorage* storage = new MtpStorage(storageID, pathStr, descriptionStr,
removable, maxFileSize);
// 通过底层的MtpServer添加这个MtpStorage对象,它会向pc端发送一个Event,通pc端,存储已经添加
server->addStorage(storage);
env->ReleaseStringUTFChars(path, pathStr);
env->ReleaseStringUTFChars(description, descriptionStr);
} else {
env->ReleaseStringUTFChars(path, pathStr);
}
}
} else {
ALOGE("server is null in add_storage");
}
}
这里转到了底层MtpServer
的addStorage()
// frameworks/av/media/mtp/MtpServer.cpp
void MtpServer::addStorage(MtpStorage* storage) {
std::lock_guard lg(mMutex);
// 保存
mStorages.push_back(storage);
// 向PC发送存储添加事件
sendStoreAdded(storage->getStorageID());
}
void MtpServer::sendStoreAdded(MtpStorageID id) {
ALOGV("sendStoreAdded %08X\n", id);
sendEvent(MTP_EVENT_STORE_ADDED, id);
}
void MtpServer::sendEvent(MtpEventCode code, uint32_t param1) {
if (mSessionOpen) {
mEvent.setEventCode(code);
mEvent.setTransactionID(mRequest.getTransactionID());
mEvent.setParameter(1, param1);
if (mEvent.write(mHandle))
ALOGE("Mtp send event failed: %s", strerror(errno));
}
}
到此,mtp的frameworks层的c++代码的工作就已经完成,剩下就是驱动层的任务了.本人的水平只能分析到jni层,到这里就不再继续深究了.
假设现在pc端已经收到这个添加存储的event,那么pc就会再次发送一系列的请求,这些请求就是用来获取存储的信息,包括存储里文件的信息.这样一来,pc端就能显示手机端存储的信息了,这就是存储的映射.
那么手机端是如何处理这些请求的呢?在分析MtpService#startServer()
时,还有最后一步没有分析,通过MtpServer#start()
方法启动一个线程来处理pc请求
// frameworks/base/media/java/android/mtp/MtpServer.java
public void start() {
Thread thread = new Thread(this, "MtpServer");
thread.start();
}
@Override
public void run() {
// 底层MtpServer执行无线循环,读取pc请求,并处理
native_run();
// 如果处理请求发生错误,那么就会执行下面的三个清理动作
native_cleanup();
mDatabase.close();
mOnTerminate.run();
}
可以看到,这里是启动了一个线程,来执行native_run()
// frameworks/base/media/jni/android_mtp_MtpServer.cpp
static void
android_mtp_MtpServer_run(JNIEnv *env, jobject thiz)
{
MtpServer* server = getMtpServer(env, thiz);
if (server)
server->run();
else
ALOGE("server is null in run");
}
它把这个处理pc请求的任务交给了MtpServer.cpp
的run()
方法
void MtpServer::run() {
// 启动usb driver
if (mHandle->start(mPtp)) {
ALOGE("Failed to start usb driver!");
mHandle->close();
return;
}
// 无线循环处理pc请求,除非发生错误
while (1) {
// 1. 读取请求
int ret = mRequest.read(mHandle);
// 2. 解析请求
MtpOperationCode operation = mRequest.getOperationCode();
MtpTransactionID transaction = mRequest.getTransactionID();
bool dataIn = (operation == MTP_OPERATION_SEND_OBJECT_INFO
|| operation == MTP_OPERATION_SET_OBJECT_REFERENCES
|| operation == MTP_OPERATION_SET_OBJECT_PROP_VALUE
|| operation == MTP_OPERATION_SET_DEVICE_PROP_VALUE);
if (dataIn) {
int ret = mData.read(mHandle);
if (ret < 0) {
ALOGE("data read returned %d, errno: %d", ret, errno);
if (errno == ECANCELED) {
// return to top of loop and wait for next command
continue;
}
break;
}
ALOGV("received data:");
} else {
mData.reset();
}
// 3. 处理请求
if (handleRequest()) {
if (!dataIn && mData.hasData()) {
mData.setOperationCode(operation);
mData.setTransactionID(transaction);
ALOGV("sending data:");
ret = mData.write(mHandle);
if (ret < 0) {
ALOGE("request write returned %d, errno: %d", ret, errno);
if (errno == ECANCELED) {
// return to top of loop and wait for next command
continue;
}
break;
}
}
mResponse.setTransactionID(transaction);
ALOGV("sending response %04X", mResponse.getResponseCode());
ret = mResponse.write(mHandle);
const int savedErrno = errno;
if (ret < 0) {
ALOGE("request write returned %d, errno: %d", ret, errno);
if (savedErrno == ECANCELED) {
// return to top of loop and wait for next command
continue;
}
break;
}
} else {
ALOGV("skipping response\n");
}
}
// 发生错误,就保存修改
int count = mObjectEditList.size();
for (int i = 0; i < count; i++) {
ObjectEdit* edit = mObjectEditList[i];
commitEdit(edit);
delete edit;
}
mObjectEditList.clear();
// 发生错误,退出
mHandle->close();
}
这里的代码是在Java层开启的线程中执行的,而且这里使用了一个无限循环来处理pc的请求,具体的代码我就不在深究了.