StorageManagerService.java中的mVold.mount
android源码:android-11.0.0_r21(网址:Search (aospxref.com))
一、问题
2243行mVold.mount执行的是哪个mount函数?
2239 private void mount(VolumeInfo vol) {
2240 try {
2241 // TODO(b/135341433): Remove paranoid logging when FUSE is stable
2242 Slog.i(TAG, "Mounting volume " + vol);
2243 mVold.mount(vol.id, vol.mountFlags, vol.mountUserId, new IVoldMountCallback.Stub() {
2244 @Override
2245 public boolean onVolumeChecking(FileDescriptor fd, String path,
2246 String internalPath) {
2247 vol.path = path;
2248 vol.internalPath = internalPath;
2249 ParcelFileDescriptor pfd = new ParcelFileDescriptor(fd);
2250 try {
2251 mStorageSessionController.onVolumeMount(pfd, vol);
2252 return true;
2253 } catch (ExternalStorageServiceException e) {
2254 Slog.e(TAG, "Failed to mount volume " + vol, e);
2255
2256 int nextResetSeconds = FAILED_MOUNT_RESET_TIMEOUT_SECONDS;
2257 Slog.i(TAG, "Scheduling reset in " + nextResetSeconds + "s");
2258 mHandler.removeMessages(H_RESET);
2259 mHandler.sendMessageDelayed(mHandler.obtainMessage(H_RESET),
2260 TimeUnit.SECONDS.toMillis(nextResetSeconds));
2261 return false;
2262 } finally {
2263 try {
2264 pfd.close();
2265 } catch (Exception e) {
2266 Slog.e(TAG, "Failed to close FUSE device fd", e);
2267 }
2268 }
2269 }
2270 });
2271 Slog.i(TAG, "Mounted volume " + vol);
2272 } catch (Exception e) {
2273 Slog.wtf(TAG, e);
2274 }
2275 }
二、分析过程
1,找到mVold变量
http://aospxref.com/android-11.0.0_r21/xref/frameworks/base/services/core/java/com/android/server/StorageManagerService.java#mVold
569 private volatile IVold mVold;
2,找到Ivold类型
http://aospxref.com/android-11.0.0_r21/xref/system/vold/binder/android/os/IVold.aidl
这是个aidl文件(Android Interface Definition Language,即Android接口定义语言),说明该文件将会定义一些函数,用于多进程间远程调用。
aidl文件经过编译后,会生成.java文件,我们可以在android编译的out目录中找到IVold.java(如果没有这个文件,也可以找到IVold.class,class反编译后得到IVold.java),IVold.java文件部分内容如下:
public interface IVold
extends IInterface {
……
static final int TRANSACTION_addSandboxIds = 11;
static final int TRANSACTION_onSecureKeyguardStateChanged = 12;
static final int TRANSACTION_partition = 13;
static final int TRANSACTION_forgetPartition = 14;
static final int TRANSACTION_mount = 15;
public void onSecureKeyguardStateChanged(boolean var1) throws RemoteException;
public void partition(String var1, int var2, int var3) throws RemoteException;
public void forgetPartition(String var1, String var2) throws RemoteException;
public void mount(String var1, int var2, int var3, IVoldMountCallback var4) throws RemoteException;
……
public static abstract class Stub
extends Binder
implements IVold {
public static IVold asInterface(IBinder obj) {
if (obj == null) {
return null;
}
IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (iin != null && iin instanceof IVold) {
return (IVold)iin;
}
return new Proxy(obj);
}
……
}
从上面代码片段可以得到如下信息:
1)IVold是个接口,继承自IInterface
2)IVold.java中定义了很多函数,与IVold.aidl中的函数对应,并且每个函数都有唯一的编号
3)IVold接口中有个Stub内部类,Stub.asInterface根据进程间通信的binder对象,找到对应的interface。举例来说,A进程实现了aidl中mount函数,B进程与A进程通过Binder-x通信,那么在B进程执行:
private volatile IVold mVold;
//根据binder找到对应的aidl interface
mVold = IVold.Stub.asInterface(Binder-x)
B进程中就可以通过mVold.mount来执行A的mount函数了。
3,IVold赋值
1928 private void connectVold() {
1929 IBinder binder = ServiceManager.getService("vold");
1930 if (binder != null) {
1931 try {
1932 binder.linkToDeath(new DeathRecipient() {
1933 @Override
1934 public void binderDied() {
1935 Slog.w(TAG, "vold died; reconnecting");
1936 mVold = null;
1937 connectVold();
1938 }
1939 }, 0);
1940 } catch (RemoteException e) {
1941 binder = null;
1942 }
1943 }
1944
1945 if (binder != null) {
1946 mVold = IVold.Stub.asInterface(binder);
1947 try {
1948 mVold.setListener(mListener);
1949 } catch (RemoteException e) {
1950 mVold = null;
1951 Slog.w(TAG, "vold listener rejected; trying again", e);
1952 }
1953 } else {
1954 Slog.w(TAG, "vold not found; trying again");
1955 }
1956
1957 if (mVold == null) {
1958 BackgroundThread.getHandler().postDelayed(() -> {
1959 connectVold();
1960 }, DateUtils.SECOND_IN_MILLIS);
1961 } else {
1962 onDaemonConnected();
1963 }
1964 }
1929行获取vold service,找到对应的binder,1946行根据binder找到对应的aidl接口mVold,找到mVold后,就可以调用其他地方实现的具体的方法了,比如mVold.mount。总结就是,找到了vold service就能找到具体的函数实现了,所以现在的问题是vold service在哪、是什么?
4,vold service是什么
如果没看过vold的启动流程,在茫茫大海的android代码里搜vold service还是比较困难的,现在直接给答案,后面再简单描述vold的启动流程。
http://aospxref.com/android-11.0.0_r21/xref/system/vold/VoldNativeService.h#31
可以看到VoldNativeService.h文件中定义了VoldNativeService类。这个类有很多函数定义,我们重点看getServiceName方法。VoldNativeService.getServiceName返回的就是“vold”,所以VoldNativeService类中的函数就是aidl接口中各个函数的具体实现。比如mVold.mount的具体实现就是VoldNativeService::mount(见VoldNativeService.cpp)。
三、vold进程的启动及vold service的注册
vold的源头在 /etc/init/hw/init.rc,系统开机后会执行这个文件,启动vold进程。init.rc对应的源码路径为: http://aospxref.com/android-11.0.0_r21/xref/system/vold/vold.rc
文件内容:
1 service vold /system/bin/vold \
2 --blkid_context=u:r:blkid:s0 --blkid_untrusted_context=u:r:blkid_untrusted:s0 \
3 --fsck_context=u:r:fsck:s0 --fsck_untrusted_context=u:r:fsck_untrusted:s0
4 class core
5 ioprio be 2
6 writepid /dev/cpuset/foreground/tasks
7 shutdown critical
8 group root reserved_disk
vold相关的源码在system/vold目录下,/system/bin/vold是从http://aospxref.com/android-11.0.0_r21/xref/system/vold/main.cpp的main函数开始执行的。 主要关注vold进程向ServiceManager注册service的过程。
54 int main(int argc, char** argv) {
……
113 ATRACE_BEGIN("VoldNativeService::start");
114 if (android::vold::VoldNativeService::start() != android::OK) {
115 LOG(ERROR) << "Unable to start VoldNativeService";
116 exit(1);
117 }
……
114行VoldNativeService::start()启动VoldNativeService,并将其注册到ServiceManager中。
http://aospxref.com/android-11.0.0_r21/xref/system/vold/VoldNativeService.cpp#120
120 status_t VoldNativeService::start() {
121 IPCThreadState::self()->disableBackgroundScheduling(true);
122 status_t ret = BinderService<VoldNativeService>::publish();
123 if (ret != android::OK) {
124 return ret;
125 }
126 sp<ProcessState> ps(ProcessState::self());
127 ps->startThreadPool();
128 ps->giveThreadPoolName();
129 return android::OK;
130 }
122行BinderService<VoldNativeService>::publish()执行具体的注册操作。
http://aospxref.com/android-11.0.0_r21/xref/frameworks/native/include/binder/BinderService.h#34
33 template<typename SERVICE>
34 class BinderService
35 {
36 public:
37 static status_t publish(bool allowIsolated = false,
38 int dumpFlags = IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT) {
39 sp<IServiceManager> sm(defaultServiceManager());
40 return sm->addService(String16(SERVICE::getServiceName()), new SERVICE(), allowIsolated,
41 dumpFlags);
根据33行typename SERVICE及 VoldNativeService::start()中122行BinderService<VoldNativeService>::publish(),可以知道SERVICE就是VoldNativeService,所以SERVICE::getServiceName()就是VoldNativeService::getServiceName()。通过第二节第4段【vold service是什么】可知getServiceName()将返回字符串“vold”。总结就是,VoldNativeService以“vold”名称注册到ServiceManager中,VoldNativeService类中实现了很多函数,这些函数就是跨进程调用的具体函数,比如mVold.mount。
四、mVold.mount是什么
在第二节第3段【IVold赋值】,1929行ServiceManager.getService("vold")获取vold service关联的binder,也就是VoldNativeService了,然后1946行mVold = IVold.Stub.asInterface(binder)获取binder对象关联的aidl接口,也就是VoldNativeService中定义的一系列接口函数了,比如mVold.mount在http://aospxref.com/android-11.0.0_r21/xref/system/vold/VoldNativeService.cpp#mount
262 binder::Status VoldNativeService::mount(
263 const std::string& volId, int32_t mountFlags, int32_t mountUserId,
264 const android::sp<android::os::IVoldMountCallback>& callback) {
265 ENFORCE_SYSTEM_OR_ROOT;
266 CHECK_ARGUMENT_ID(volId);
267 ACQUIRE_LOCK;
268
269 auto vol = VolumeManager::Instance()->findVolume(volId);
270 if (vol == nullptr) {
271 return error("Failed to find volume " + volId);
272 }
273
274 vol->setMountFlags(mountFlags);
275 vol->setMountUserId(mountUserId);
276
277 vol->setMountCallback(callback);
278 int res = vol->mount();
279 vol->setMountCallback(nullptr);
280
281 if (res != OK) {
282 return translate(res);
283 }
284
285 if ((mountFlags & MOUNT_FLAG_PRIMARY) != 0) {
286 res = VolumeManager::Instance()->setPrimary(vol);
287 if (res != OK) {
288 return translate(res);
289 }
290 }
291 return translate(OK);
292 }
【推荐】还在用 ECharts 开发大屏?试试这款永久免费的开源 BI 工具!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步