Jimmy Chen

A Programmer

(原创)Android FBE加密源码分析(一)

  书接上一回,上一回我们讲到分区的mount过程,这一回我们将剩下的加密内容也一同分析下。

接上一篇 fs_mgr_mount_all 开始

上一篇只讲到mount_with_alternatives函数就没有继续讲下去了,这里我们从这里开始讲。同样的,这里我们还是用userdata这一个分区作为例子。userdata在fstab.sailfish的内容也先贴出来。

/dev/block/platform/soc/624000.ufshc/by-name/userdata   /data               ext4    errors=panic,noatime,nosuid,nodev,barrier=1,noauto_da_alloc  latemount,wait,check,formattable,fileencryption=ice,quota

下面开始看代码

        ..................
        // 上一篇讲到,userdata是mount成功的,最后这里返回0,所以mret=0
        mret = mount_with_alternatives(fstab, i, &last_idx_inspected, &attempted_idx);
        i = last_idx_inspected;
        mount_errno = errno;

        /* Deal with encryptability. */
        if (!mret) {
            // mret=0走这里,handle_encryptable下面分析
            // 下面分析的内容可以知道,这里status=FS_MGR_MNTALL_DEV_FILE_ENCRYPTED
            int status = handle_encryptable(&fstab->recs[attempted_idx]);

            if (status == FS_MGR_MNTALL_FAIL) {
                /* Fatal error - no point continuing */
                return status;
            }

            // if条件为true
            if (status != FS_MGR_MNTALL_DEV_NOT_ENCRYPTABLE) {
                // if条件为false
                if (encryptable != FS_MGR_MNTALL_DEV_NOT_ENCRYPTABLE) {
                    // Log and continue
                    LERROR << "Only one encryptable/encrypted partition supported";
                }
                // 最终encrytable=status=FS_MGR_MNTALL_DEV_FILE_ENCRYPTED
                encryptable = status;
            }

            // OK,跳过剩余的代码。
            continue;
        }

        bool wiped = partition_wiped(fstab->recs[top_idx].blk_device);
        bool crypt_footer = false;
        if (mret && mount_errno != EBUSY && mount_errno != EACCES &&
            fs_mgr_is_formattable(&fstab->recs[top_idx]) && wiped) {
            LERROR << __FUNCTION__ << "(): " << fstab->recs[top_idx].blk_device
                   << " is wiped and " << fstab->recs[top_idx].mount_point
                   << " " << fstab->recs[top_idx].fs_type
                   << " is formattable. Format it.";
        ....................

    if (error_count) {
        return FS_MGR_MNTALL_FAIL;
    } else {
        // 返回encrytable=FS_MGR_MNTALL_DEV_FILE_ENCRYPTED
        return encryptable;
    }

fs_mgr_mount_all --> handle_encryptable

这里查看userdata在fstabl.sailfish中的标志位带有"fileencryption=",对比上一篇中的fs_mgr_flags[]数组可以知道,"fileencryption="对应于MF_FILEENCRYPTION。这接下来的代码就是比较对应分区信息中是都带有对应的标志的。

// Check to see if a mountable volume has encryption requirements
static int handle_encryptable(const struct fstab_rec* rec)
{
    // 从下面的分析可知,函数调用返回false
    if (needs_block_encryption(rec)) {
        if (umount(rec->mount_point) == 0) {
            return FS_MGR_MNTALL_DEV_NEEDS_ENCRYPTION;
        } else {
            PWARNING << "Could not umount " << rec->mount_point
                     << " - allow continue unencrypted";
            return FS_MGR_MNTALL_DEV_NOT_ENCRYPTED;
        }
    // 下面分析,函数调用返回false
    } else if (should_use_metadata_encryption(rec)) {
        if (umount(rec->mount_point) == 0) {
            return FS_MGR_MNTALL_DEV_NEEDS_METADATA_ENCRYPTION;
        } else {
            PERROR << "Could not umount " << rec->mount_point << " - fail since can't encrypt";
            return FS_MGR_MNTALL_FAIL;
        }
    // flags匹配MF_FILEENCRYPTION,所以函数返回FS_MGR_MNTALL_DEV_FILE_ENCRYPTED
    } else if (rec->fs_mgr_flags & (MF_FILEENCRYPTION | MF_FORCEFDEORFBE)) {
        LINFO << rec->mount_point << " is file encrypted";
        return FS_MGR_MNTALL_DEV_FILE_ENCRYPTED;
    } else if (fs_mgr_is_encryptable(rec)) {
        return FS_MGR_MNTALL_DEV_NOT_ENCRYPTED;
    } else {
        return FS_MGR_MNTALL_DEV_NOT_ENCRYPTABLE;
    }
}

handle_encryptable --> needs_block_encryption

static bool needs_block_encryption(const struct fstab_rec* rec)
{
    /* 
       device_is_force_encrypted是通过读取ro.vold.forceencryption熟悉来判断的
       明显系统中没有定义该属性值。返回false
       fs_mgr_is_encryptable是通过对比分区表的flags是否符合条件来判断的。返回false
    */
    if (device_is_force_encrypted() && fs_mgr_is_encryptable(rec)) return true;
    // 下面if条件为false
    if (rec->fs_mgr_flags & MF_FORCECRYPT) return true;
    // if条件为false
    if (rec->fs_mgr_flags & MF_CRYPT) {
        /* Check for existence of convert_fde breadcrumb file */
        char convert_fde_name[PATH_MAX];
        snprintf(convert_fde_name, sizeof(convert_fde_name),
                 "%s/misc/vold/convert_fde", rec->mount_point);
        if (access(convert_fde_name, F_OK) == 0) return true;
    }
    // if条件为false
    if (rec->fs_mgr_flags & MF_FORCEFDEORFBE) {
        /* Check for absence of convert_fbe breadcrumb file */
        char convert_fbe_name[PATH_MAX];
        snprintf(convert_fbe_name, sizeof(convert_fbe_name),
                 "%s/convert_fbe", rec->mount_point);
        if (access(convert_fbe_name, F_OK) != 0) return true;
    }
    return false;
}

handle_encryptable --> should_use_metadata_encryption

static bool should_use_metadata_encryption(const struct fstab_rec* rec) {
    if (!(rec->fs_mgr_flags & (MF_FILEENCRYPTION | MF_FORCEFDEORFBE))) return false;
    // 下面的if条件判断为true,所以返回false
    if (!(rec->fs_mgr_flags & MF_KEYDIRECTORY)) return false;
    return true;
}

到这里,加密部分对应的参数就分析OK了,接下来就是从fs_mgr_mount_all函数向上弹出调用栈,首先是回到mount_fstab函数中。

mount_fstab

上一篇说到mount_fstab会创建一个线程执行mount操作,而父进程则等待子线程返回,并获取返回值。

static int mount_fstab(const char* fstabfile, int mount_mode) {
    int ret = -1;

    pid_t pid = fork();
    if (pid > 0) {
        /* Parent.  Wait for the child to return */
        int status;
        int wp_ret = TEMP_FAILURE_RETRY(waitpid(pid, &status, 0));
        if (wp_ret == -1) {
            // Unexpected error code. We will continue anyway.
            PLOG(WARNING) << "waitpid failed";
        }

        if (WIFEXITED(status)) {
            // 执行ret=FS_MGR_MNTALL_DEV_FILE_ENCRYPTED
            ret = WEXITSTATUS(status);
        } else {
            ret = -1;
        }
    } else if (pid == 0) {
        android::base::ScopedLogSeverity info(android::base::INFO);

        struct fstab* fstab = fs_mgr_read_fstab(fstabfile);
        // 在这里返回child_ret = FS_MGR_MNTALL_DEV_FILE_ENCRYPTED
        int child_ret = fs_mgr_mount_all(fstab, mount_mode);
        fs_mgr_free_fstab(fstab);
        if (child_ret == -1) {
            PLOG(ERROR) << "fs_mgr_mount_all returned an error";
        }
        // 将执行结果返回给父进程
        _exit(child_ret);
    } else {
        /* fork failed, return an error */
        return -1;
    }
    // 最终mount_fstab也是返回FS_MGR_MNTALL_DEV_FILE_ENCRYPTED
    return ret;
}

这一步OK,再往上出栈就到do_mount_all了。

do_mount_all

static int do_mount_all(const std::vector<std::string>& args) {
    std::size_t na = 0;
    bool import_rc = true;
    bool queue_event = true;
    int mount_mode = MOUNT_MODE_DEFAULT;
    const char* fstabfile = args[1].c_str();
    std::size_t path_arg_end = args.size();
    const char* prop_post_fix = "default";

    for (na = args.size() - 1; na > 1; --na) {
        if (args[na] == "--early") {
            path_arg_end = na;
            queue_event = false;
            mount_mode = MOUNT_MODE_EARLY;
            prop_post_fix = "early";
        } else if (args[na] == "--late") {
            path_arg_end = na;
            import_rc = false;
            mount_mode = MOUNT_MODE_LATE;
            prop_post_fix = "late";
        }
    }

    std::string prop_name = "ro.boottime.init.mount_all."s + prop_post_fix;
    android::base::Timer t;
    // mount_fstab返回FS_MGR_MNTALL_DEV_FILE_ENCRYPTED
    int ret =  mount_fstab(fstabfile, mount_mode);
    property_set(prop_name, std::to_string(t.duration().count()));

    // userdata在--late阶段,这里不用管
    if (import_rc) {
        /* Paths of .rc files are specified at the 2nd argument and beyond */
        import_late(args, 2, path_arg_end);
    }

    // 下面看queue_fs_evenet
    if (queue_event) {
        /* queue_fs_event will queue event based on mount_fstab return code
         * and return processed return code*/
        ret = queue_fs_event(ret);
    }

    return ret;
}

do_mount_all --> queue_fs_event

static int queue_fs_event(int code) {
    int ret = code;
    ..............
        /* If reboot worked, there is no return. */
    } else if (code == FS_MGR_MNTALL_DEV_FILE_ENCRYPTED) {
        if (e4crypt_install_keyring()) {
            return -1;
        }
        // 设置两个属性
        property_set("ro.crypto.state", "encrypted");
        property_set("ro.crypto.type", "file");

        // 什么,最后出发的是"nonencrypted"这个event,那不就是说什么都不做?
        ActionManager::GetInstance().QueueEventTrigger("nonencrypted");
    } else if (code == FS_MGR_MNTALL_DEV_IS_METADATA_ENCRYPTED) {
        if (e4crypt_install_keyring()) {
            return -1;
        }

    ................
    return ret;
}

只看相关的内容,其余部分省略掉。首先看key的安装。

queue_fs_event --> e4crypt_install_keyring

int e4crypt_install_keyring()
{
    // 这个我最后跟到syscalls.h文件中找到定义就跟不下去了,看函数前缀应该是会变函数,具体不清楚
    // 不过看名字应该是添加key内容的
    key_serial_t device_keyring = add_key("keyring", "e4crypt", 0, 0,
                                          KEY_SPEC_SESSION_KEYRING);

    if (device_keyring == -1) {
        PLOG(ERROR) << "Failed to create keyring";
        return -1;
    }

    LOG(INFO) << "Keyring created with id " << device_keyring << " in process " << getpid();

    return 0;
}

这里,在do_mount_all的最后触发了"nonencrypted" event。看这个event的内容只是简单启动late_start和main类的应用。看来这个加密过程还要在稍后的地方进行啊。

on_post_fs阶段

on post-fs-data
    # We chown/chmod /data again so because mount is run as root + defaults
    chown system system /data
    chmod 0771 /data
    # We restorecon /data in case the userdata partition has been reset.
    restorecon /data

    # Make sure we have the device encryption key.
    start vold
    installkey /data
    ................

这里,我们从installkey开始,对照function map,installkey这个action对应的函数是do_intallkey

static int do_installkey(const std::vector<std::string>& args) {
    // 如果不是基于文件级加密,返回0
    if (!is_file_crypto()) {
        return 0;
    }
    // unencrypted_dir="/data/unencrypted"
    auto unencrypted_dir = args[1] + e4crypt_unencrypted_folder;
    if (do_installkeys_ensure_dir_exists(unencrypted_dir.c_str())) {
        PLOG(ERROR) << "Failed to create " << unencrypted_dir;
        return -1;
    }
    // 设置启动vdc进程的参数
    std::vector<std::string> exec_args = {"exec", "/system/bin/vdc", "--wait", "cryptfs",
                                        "enablefilecrypto"};
    // 创建一个新的进程vdc
    return do_exec(exec_args);
}

do_installkey --> vdc::main()

// /system/bin/vdc --wait cryptfs enablefilecrypto
// 所以argc=4
int main(int argc, char **argv) {
    int sock;
    int wait_for_socket;
    char *progname;

    // progname="/system/bin/vdc"
    progname = argv[0];

    // log输出位置选择
    if (getppid() == 1) {
        // If init is calling us then it's during boot and we should log to kmsg
        android::base::InitLogging(argv, &android::base::KernelLogger);
    } else {
        android::base::InitLogging(argv, &android::base::StderrLogger);
    }

    // 根据传入参数,wait_for_socket=1
    wait_for_socket = argc > 1 && strcmp(argv[1], "--wait") == 0;
    if (wait_for_socket) {
        argv++;
        argc--;
    }

    if (argc < 2) {
        usage(progname);
        exit(5);
    }

    // socket连接对端的名字"vold"
    const char* sockname = "vold";
    if (!strcmp(argv[1], "cryptfs")) {
        // 最后还是讲sockname设置为"cryptd"
        sockname = "cryptd";
    }

    // 连接到cryptd
    while ((sock = socket_local_client(sockname,
                                 ANDROID_SOCKET_NAMESPACE_RESERVED,
                                 SOCK_STREAM)) < 0) {
        if (!wait_for_socket) {
            PLOG(ERROR) << "Error connecting to " << sockname;
            exit(4);
        } else {
            usleep(10000);
        }
    }

    // 执行do_cmd
    if (!strcmp(argv[1], "monitor")) {
        exit(do_monitor(sock, 0));
    } else {
        // argc=3,argv="--wait cryptfs enablefilecrypto"
        exit(do_cmd(sock, argc, argv));
    }
}

vdc::main() --> do_cmd

static int do_cmd(int sock, int argc, char **argv) {
    // 获取当前进程PID
    int seq = getpid();

    // 设置字符串CMD="PID cryptfs enablefilecrypto"
    std::string cmd(android::base::StringPrintf("%d ", seq));
    for (int i = 1; i < argc; i++) {
        if (!strchr(argv[i], ' ')) {
            cmd.append(argv[i]);
        } else {
            cmd.push_back('\"');
            cmd.append(argv[i]);
            cmd.push_back('\"');
        }

        if (i < argc - 1) {
            cmd.push_back(' ');
        }
    }

    // 讲数据传输到对端,即cryptd
    if (TEMP_FAILURE_RETRY(write(sock, cmd.c_str(), cmd.length() + 1)) < 0) {
        PLOG(ERROR) << "Failed to write command";
        return errno;
    }

    // 执行do_monitor等待回来的数据
    return do_monitor(sock, seq);
}

vdc通过socket通信的方式,和cryptd建立连接,并通过write见cmd数据写到cryptd中。最后通过do_monitor等待处理的结果并对结果进行分析。在分析cryptd是如何处理数据前,需要先弄清楚cryptd这个socket server端是什么时候启动起来的。

Vold启动分析

  看回前面init.rc中的op-post-fs阶段,在installkey前,有先执行start vold,所以呢,在执行installkey前,vold是会先启动的。vold的代码在system/vold/main.cpp中

main.cpp::main()

int main(int argc, char** argv) {
    setenv("ANDROID_LOG_TAGS", "*:v", 1);
    android::base::InitLogging(argv, android::base::LogdLogger(android::base::SYSTEM));

    // 输出log信息
    LOG(INFO) << "Vold 3.0 (the awakening) firing up";

    LOG(VERBOSE) << "Detected support for:"
            << (android::vold::IsFilesystemSupported("ext4") ? " ext4" : "")
            << (android::vold::IsFilesystemSupported("f2fs") ? " f2fs" : "")
            << (android::vold::IsFilesystemSupported("vfat") ? " vfat" : "");

    // 创建一些Manager和Listener
    VolumeManager *vm;
    CommandListener *cl;
    CryptCommandListener *ccl;
    NetlinkManager *nm;

    parse_args(argc, argv);

    // Selinux设置
    sehandle = selinux_android_file_context_handle();
    if (sehandle) {
        selinux_android_set_sehandle(sehandle);
    }

    // Quickly throw a CLOEXEC on the socket we just inherited from init
    // 获取对应socket的控制权,可以看到这里就有名为"cryptd"的socket
    fcntl(android_get_control_socket("vold"), F_SETFD, FD_CLOEXEC);
    fcntl(android_get_control_socket("cryptd"), F_SETFD, FD_CLOEXEC);

    mkdir("/dev/block/vold", 0755);

    /* For when cryptfs checks and mounts an encrypted filesystem */
    klog_set_level(6);

    /* Create our singleton managers */
    if (!(vm = VolumeManager::Instance())) {
        LOG(ERROR) << "Unable to create VolumeManager";
        exit(1);
    }

    if (!(nm = NetlinkManager::Instance())) {
        LOG(ERROR) << "Unable to create NetlinkManager";
        exit(1);
    }

    if (property_get_bool("vold.debug", false)) {
        vm->setDebug(true);
    }

    // 这两个listener下面再讲解
    cl = new CommandListener();
    ccl = new CryptCommandListener();
    vm->setBroadcaster((SocketListener *) cl);
    nm->setBroadcaster((SocketListener *) cl);

    if (vm->start()) {
        PLOG(ERROR) << "Unable to start VolumeManager";
        exit(1);
    }

    bool has_adoptable;
    bool has_quota;

    if (process_config(vm, &has_adoptable, &has_quota)) {
        PLOG(ERROR) << "Error reading configuration... continuing anyways";
    }

    if (nm->start()) {
        PLOG(ERROR) << "Unable to start NetlinkManager";
        exit(1);
    }

    // 启动Listener
    if (cl->startListener()) {
        PLOG(ERROR) << "Unable to start CommandListener";
        exit(1);
    }

    if (ccl->startListener()) {
        PLOG(ERROR) << "Unable to start CryptCommandListener";
        exit(1);
    }

    // 设置属性
    property_set("vold.has_adoptable", has_adoptable ? "1" : "0");
    property_set("vold.has_quota", has_quota ? "1" : "0");

    // Do coldboot here so it won't block booting,
    // also the cold boot is needed in case we have flash drive
    // connected before Vold launched
    coldboot("/sys/block");
    // Eventually we'll become the monitoring thread
    while(1) {
        pause();
    }

    LOG(ERROR) << "Vold exiting";
    exit(0);
}

既然前面doInstallkey是通过socket来传输指令的,那当然要分析下socket的服务端是怎么启动的。

new CryptCommandListener()

// CryptCommandListener是从FrameworkListener继承而来
CryptCommandListener::CryptCommandListener() :
// "cryptd"是socket的名字
FrameworkListener("cryptd", true) {
    // 注册不同的命令对象
    registerCmd(new CryptfsCmd());
}

// socketName="cryptd", withSeq=true
FrameworkListener::FrameworkListener(const char *socketName, bool withSeq) :
                            SocketListener(socketName, true, withSeq) {
    init(socketName, withSeq);
}

// FrameworkListener --> init
void FrameworkListener::init(const char *socketName UNUSED, bool withSeq) {
    mCommands = new FrameworkCommandCollection();
    errorRate = 0;
    mCommandCount = 0;
    mWithSeq = withSeq;
    mSkipToNextNullByte = false;
}


// FrameworkListener --> SocketListener
// socketName="cryptd",listen=true,withSeq=true
SocketListener::SocketListener(const char *socketName, bool listen, bool useCmdNum) {
    init(socketName, -1, listen, useCmdNum);
}


// SocketListener --> init
void SocketListener::init(const char *socketName, int socketFd, bool listen, bool useCmdNum) {
    // 标记是否是服务端
    mListen = listen;
    // Socket名字
    mSocketName = socketName;
    // socket文件描述符
    mSock = socketFd;
    mUseCmdNum = useCmdNum;
    pthread_mutex_init(&mClientsLock, NULL);
    // 集合对象
    mClients = new SocketClientCollection();
}

ccl->startListener()

int SocketListener::startListener() {
    return startListener(4);
}

int SocketListener::startListener(int backlog) {

    // 从前面的初始化可以知道mSocketName不为NULL
    if (!mSocketName && mSock == -1) {
        SLOGE("Failed to start unbound listener");
        errno = EINVAL;
        return -1;
    } else if (mSocketName) {
        // 获取Socket的控制权
        if ((mSock = android_get_control_socket(mSocketName)) < 0) {
            SLOGE("Obtaining file descriptor socket '%s' failed: %s",
                 mSocketName, strerror(errno));
            return -1;
        }
        SLOGV("got mSock = %d for %s", mSock, mSocketName);
        fcntl(mSock, F_SETFD, FD_CLOEXEC);
    }

    // 如果是服务端就开始监听请求
    if (mListen && listen(mSock, backlog) < 0) {
        SLOGE("Unable to listen on socket (%s)", strerror(errno));
        return -1;
    } else if (!mListen)
        mClients->push_back(new SocketClient(mSock, false, mUseCmdNum));

    if (pipe(mCtrlPipe)) {
        SLOGE("pipe failed (%s)", strerror(errno));
        return -1;
    }

    // 创建线程threadStart处理客户端的连接
    if (pthread_create(&mThread, NULL, SocketListener::threadStart, this)) {
        SLOGE("pthread_create (%s)", strerror(errno));
        return -1;
    }

    return 0;
}

// 创建的工作线程
void *SocketListener::threadStart(void *obj) {
    SocketListener *me = reinterpret_cast<SocketListener *>(obj);

    me->runListener();
    pthread_exit(NULL);
    return NULL;
}

// 实际的工作函数
void SocketListener::runListener() {

    SocketClientCollection pendingList;

    // 循环处理
    while(1) {
        SocketClientCollection::iterator it;
        // 通过select监控需要处理的socket句柄
        fd_set read_fds;
        int rc = 0;
        int max = -1;

        FD_ZERO(&read_fds);

        // 如果是服务端,将服务端句柄也加入到select中监控
        if (mListen) {
            max = mSock;
            FD_SET(mSock, &read_fds);
        }

        FD_SET(mCtrlPipe[0], &read_fds);
        if (mCtrlPipe[0] > max)
            max = mCtrlPipe[0];

        pthread_mutex_lock(&mClientsLock);
        // 将连接的client句柄加入监控
        for (it = mClients->begin(); it != mClients->end(); ++it) {
            // NB: calling out to an other object with mClientsLock held (safe)
            int fd = (*it)->getSocket();
            FD_SET(fd, &read_fds);
            if (fd > max) {
                max = fd;
            }
        }
        pthread_mutex_unlock(&mClientsLock);
        SLOGV("mListen=%d, max=%d, mSocketName=%s", mListen, max, mSocketName);
        if ((rc = select(max + 1, &read_fds, NULL, NULL, NULL)) < 0) {
            if (errno == EINTR)
                continue;
            SLOGE("select failed (%s) mListen=%d, max=%d", strerror(errno), mListen, max);
            sleep(1);
            continue;
        } else if (!rc)
            continue;
        
        // 如果有数据或者请求到来
        if (FD_ISSET(mCtrlPipe[0], &read_fds)) {
            char c = CtrlPipe_Shutdown;
            TEMP_FAILURE_RETRY(read(mCtrlPipe[0], &c, 1));
            if (c == CtrlPipe_Shutdown) {
                break;
            }
            continue;
        }
        // 如果是服务端,而且有请求链接到来
        if (mListen && FD_ISSET(mSock, &read_fds)) {
            int c = TEMP_FAILURE_RETRY(accept4(mSock, nullptr, nullptr, SOCK_CLOEXEC));
            if (c < 0) {
                SLOGE("accept failed (%s)", strerror(errno));
                sleep(1);
                continue;
            }
            pthread_mutex_lock(&mClientsLock);
            // 将服务端信息加入到mClient中
            mClients->push_back(new SocketClient(c, true, mUseCmdNum));
            pthread_mutex_unlock(&mClientsLock);
        }

        /* Add all active clients to the pending list first */
        pendingList.clear();
        pthread_mutex_lock(&mClientsLock);
        // 迭代记录那些处于活跃状态的client,即那些有数据到达的client
        for (it = mClients->begin(); it != mClients->end(); ++it) {
            SocketClient* c = *it;
            // NB: calling out to an other object with mClientsLock held (safe)
            int fd = c->getSocket();
            if (FD_ISSET(fd, &read_fds)) {
                // 将活跃的client添加到pendingList中
                pendingList.push_back(c);
                c->incRef();
            }
        }
        pthread_mutex_unlock(&mClientsLock);

        // pendingList不为空,开始处理数据 
        while (!pendingList.empty()) {
            /* Pop the first item from the list */
            it = pendingList.begin();
            SocketClient* c = *it;
            pendingList.erase(it);
            /* Process it, if false is returned, remove from list */
            if (!onDataAvailable(c)) {
                release(c, false);
            }
            c->decRef();
        }
    }
}

cryptd的启动流程知道了,下面继续看看是怎么处理client到达的数据的吧。首先根据纯虚函数和继承可以知道,最后调用的onDataAvailable是FrameworkListener::onDataAvailable,然后FrameworkListener::onDataAvailable会调用到FrameworkListener::dispatchCommand

FrameworkListener::onDataAvailable

bool FrameworkListener::onDataAvailable(SocketClient *c) {
    char buffer[CMD_BUF_SIZE];
    int len;

    len = TEMP_FAILURE_RETRY(read(c->getSocket(), buffer, sizeof(buffer)));
    if (len < 0) {
        SLOGE("read() failed (%s)", strerror(errno));
        return false;
    } else if (!len) {
        return false;
    } else if (buffer[len-1] != '\0') {
        SLOGW("String is not zero-terminated");
        android_errorWriteLog(0x534e4554, "29831647");
        c->sendMsg(500, "Command too large for buffer", false);
        mSkipToNextNullByte = true;
        return true;
    }

    int offset = 0;
    int i;

    for (i = 0; i < len; i++) {
        if (buffer[i] == '\0') {
            /* IMPORTANT: dispatchCommand() expects a zero-terminated string */
            if (mSkipToNextNullByte) {
                mSkipToNextNullByte = false;
            } else {
                dispatchCommand(c, buffer + offset);
            }
            offset = i + 1;
        }
    }

    mSkipToNextNullByte = false;
    return true;
}

FrameworkListener::dispatchCommand() --> FrameworkListener::dispatchCommand

void FrameworkListener::dispatchCommand(SocketClient *cli, char *data) {
    // 下面的代码主要是对传进来的data进行解析,具体代码就不贴出来了
    FrameworkCommandCollection::iterator i;
    int argc = 0;
    char *argv[FrameworkListener::CMD_ARGS_MAX];
    char tmp[CMD_BUF_SIZE];

    ...................


    if (errorRate && (++mCommandCount % errorRate == 0)) {
        /* ignore this command - let the timeout handler handle it */
        SLOGE("Faking a timeout");
        goto out;
    }

    for (i = mCommands->begin(); i != mCommands->end(); ++i) {
        FrameworkCommand *c = *i;

        if (!strcmp(argv[0], c->getCommand())) {
            // 最后在调用runCommand来执行具体的操作
            if (c->runCommand(cli, argc, argv)) {
                SLOGW("Handler '%s' error (%s)", c->getCommand(), strerror(errno));
            }
            goto out;
        }
    }
    cli->sendMsg(500, "Command not recognized", false);
out:
    int j;
    for (j = 0; j < argc; j++)
        free(argv[j]);
    return;

overflow:
    cli->sendMsg(500, "Command too long", false);
    goto out;
}

好了好了,这一篇感觉长了,就想到这里,剩下的会在另一篇里在做分析。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d 博主赞过: