Android应用权限源码分析

2019年6月20日

问题症状

void FieldInstrumentationListener::OpenPerfLog() {

  std::string pid_str = std::to_string(getpid());
  time_t n = time(nullptr);
  struct tm* local = localtime(&n);
  char strTime[80];
  strftime(strTime, 80, "%Y-%m-%d %H-%M-%S", local);
  std::string perf_filename = std::string(kLogPrefix) + "/nvm-" + strTime + "-" + pid_str + ".log";

  if(log.is_open()) {
    log.close();
  }

  log = std::ofstream(perf_filename.c_str());
  struct passwd *pwd = getpwuid(getuid());
  DCHECK_EQ(pwd->pw_uid, getuid());
  if (log.is_open())
    LOG(INFO) << "User " << pwd->pw_name << "(" << pwd->pw_uid << ") created field instrumentation log is created at " << perf_filename;
  else {
    LOG(WARNING) << "User " << pwd->pw_name << "(" << pwd->pw_uid << ") cannot opening field instrumentation log at " << perf_filename << ". Error: " << strerror(errno);
  }
}
[19:18:51]->~/Project/WORKING_DIRECTORY$ adb logcat | grep -F "instrumentation log"
04-23 15:28:31.665  2382  2382 W zygote64: User bluetooth(1002) cannot opening field instrumentation log at /storage/self/primary/nvm-1970-04-23 15-28-31-2382.log. Error: No such file or directory
04-23 15:28:31.746  2419  2419 W zygote64: User u0_a50(10050) cannot opening field instrumentation log at /storage/self/primary/nvm-1970-04-23 15-28-31-2419.log. Error: No such file or directory
04-23 15:28:31.810  2455  2455 W zygote64: User u0_a26(10026) cannot opening field instrumentation log at /storage/self/primary/nvm-1970-04-23 15-28-31-2455.log. Error: No such file or directory
04-23 15:28:31.897  2509  2509 W zygote  : User shared_relro(1037) cannot opening field instrumentation log at /storage/self/primary/nvm-1970-04-23 15-28-31-2509.log. Error: No such file or directory
04-23 15:28:31.926  2530  2530 W zygote64: User shared_relro(1037) cannot opening field instrumentation log at /storage/self/primary/nvm-1970-04-23 15-28-31-2530.log. Error: No such file or directory
04-23 15:28:32.168  2722  2722 W zygote64: User system(1000) cannot opening field instrumentation log at /storage/self/primary/nvm-1970-04-23 15-28-32-2722.log. Error: No such file or directory
04-23 15:28:32.362  2868  2868 W zygote64: User system(1000) cannot opening field instrumentation log at /storage/self/primary/nvm-1970-04-23 15-28-32-2868.log. Error: No such file or directory
04-23 15:28:34.088  3413  3413 W zygote64: User u0_a11(10011) cannot opening field instrumentation log at /storage/self/primary/nvm-1970-04-23 15-28-34-3413.log. Error: No such file or directory
04-23 15:28:34.390  3521  3521 W zygote64: User u0_a44(10044) cannot opening field instrumentation log at /storage/self/primary/nvm-1970-04-23 15-28-34-3521.log. Error: Permission denied
04-23 15:28:34.517  3581  3581 I zygote64: User nfc(1027) created field instrumentation log is created at /storage/self/primary/nvm-1970-04-23 15-28-34-3581.log
04-23 15:28:34.539  3597  3597 W zygote64: User u0_a57(10057) cannot opening field instrumentation log at /storage/self/primary/nvm-1970-04-23 15-28-34-3597.log. Error: Permission denied
04-23 15:28:34.620  3641  3641 W zygote64: User u0_a15(10015) cannot opening field instrumentation log at /storage/self/primary/nvm-1970-04-23 15-28-34-3641.log. Error: Permission denied
04-23 15:28:34.656  3660  3660 W zygote64: User u0_a19(10019) cannot opening field instrumentation log at /storage/self/primary/nvm-1970-04-23 15-28-34-3660.log. Error: Permission denied
04-23 15:28:34.743  3718  3718 I zygote64: User system(1000) created field instrumentation log is created at /storage/self/primary/nvm-1970-04-23 15-28-34-3718.log
04-23 15:28:35.728  3841  3841 W zygote64: User u0_a16(10016) cannot opening field instrumentation log at /storage/self/primary/nvm-1970-04-23 15-28-35-3841.log. Error: Permission denied
04-23 15:28:35.817  3860  3860 W zygote64: User u0_a58(10058) cannot opening field instrumentation log at /storage/self/primary/nvm-1970-04-23 15-28-35-3860.log. Error: Permission denied
04-23 15:28:35.928  3886  3886 I zygote64: User u0_a3(10003) created field instrumentation log is created at /storage/self/primary/nvm-1970-04-23 15-28-35-3886.log
04-23 15:28:36.217  3906  3906 W zygote64: User u0_a2(10002) cannot opening field instrumentation log at /storage/self/primary/nvm-1970-04-23 15-28-36-3906.log. Error: Permission denied
04-23 15:28:36.392  3968  3968 W zygote64: User u0_a59(10059) cannot opening field instrumentation log at /storage/self/primary/nvm-1970-04-23 15-28-36-3968.log. Error: Permission denied
04-23 15:28:37.892  4189  4189 W zygote64: User u0_a13(10013) cannot opening field instrumentation log at /storage/self/primary/nvm-1970-04-23 15-28-37-4189.log. Error: Permission denied
04-23 15:28:38.359  4233  4233 W zygote64: User u0_a36(10036) cannot opening field instrumentation log at /storage/self/primary/nvm-1970-04-23 15-28-38-4233.log. Error: Permission denied
04-23 15:28:38.549  4289  4289 I zygote64: User u0_a39(10039) created field instrumentation log is created at /storage/self/primary/nvm-1970-04-23 15-28-38-4289.log
04-23 15:28:38.738  4309  4309 W zygote64: User u0_a8(10008) cannot opening field instrumentation log at /storage/self/primary/nvm-1970-04-23 15-28-38-4309.log. Error: Permission denied
04-23 15:28:38.881  4328  4328 W zygote64: User u0_a7(10007) cannot opening field instrumentation log at /storage/self/primary/nvm-1970-04-23 15-28-38-4328.log. Error: Permission denied
04-23 15:28:39.194  4373  4373 I zygote64: User u0_a45(10045) created field instrumentation log is created at /storage/self/primary/nvm-1970-04-23 15-28-39-4373.log
04-23 15:28:39.797  4425  4425 I zygote64: User u0_a48(10048) created field instrumentation log is created at /storage/self/primary/nvm-1970-04-23 15-28-39-4425.log
04-23 15:28:40.014  4441  4441 I zygote64: User u0_a62(10062) created field instrumentation log is created at /storage/self/primary/nvm-1970-04-23 15-28-40-4441.log
04-23 15:28:40.320  4460  4460 W zygote64: User u0_a17(10017) cannot opening field instrumentation log at /storage/self/primary/nvm-1970-04-23 15-28-40-4460.log. Error: Permission denied
04-23 15:28:40.551  4505  4505 W zygote64: User u0_a21(10021) cannot opening field instrumentation log at /storage/self/primary/nvm-1970-04-23 15-28-40-4505.log. Error: Permission denied
04-23 15:29:02.961  4821  4821 I zygote64: User system(1000) created field instrumentation log is created at /storage/self/primary/nvm-1970-04-23 15-29-02-4821.log
04-23 15:29:29.317  4891  4891 W zygote64: User u0_a47(10047) cannot opening field instrumentation log at /storage/self/primary/nvm-1970-04-23 15-29-29-4891.log. Error: Permission denied
04-23 15:29:55.592  5012  5012 W zygote64: User u0_a2(10002) cannot opening field instrumentation log at /storage/self/primary/nvm-1970-04-23 15-29-55-5012.log. Error: Permission denied
04-23 15:31:29.829  5084  5084 I zygote64: User u0_a5(10005) created field instrumentation log is created at /storage/self/primary/nvm-1970-04-23 15-31-29-5084.log
04-23 15:32:07.743  5144  5144 W zygote64: User u0_a23(10023) cannot opening field instrumentation log at /storage/self/primary/nvm-1970-04-23 15-32-07-5144.log. Error: Permission denied
04-23 15:32:16.602  5217  5217 W zygote  : User u0_a63(10063) cannot opening field instrumentation log at /storage/self/primary/nvm-1970-04-23 15-32-16-5217.log. Error: Permission denied
04-23 15:32:23.596  5405  5405 W zygote  : User u0_a54(10054) cannot opening field instrumentation log at /storage/self/primary/nvm-1970-04-23 15-32-23-5405.log. Error: Permission denied
^C

经测试,发现AndroidManifest.xml申请并且用户允许了android.permission.WRITE_EXTERNAL_STORAGE权限,C++代码才能在/sdcard/文件夹成功创建文件。

这个限制似乎深入到Linux系统调用open。

frameworks/base/core/jni/com_android_internal_os_Zygote.cpp文件的MountEmulatedStorage方法里有

// Create a private mount namespace and bind mount appropriate emulated
// storage for the given user.
static bool MountEmulatedStorage(uid_t uid, jint mount_mode,
        bool force_mount_namespace) {
    // See storage config details at http://source.android.com/tech/storage/  //应为https://source.android.com/devices/storage

    String8 storageSource;
    if (mount_mode == MOUNT_EXTERNAL_DEFAULT) {
        storageSource = "/mnt/runtime/default";
    } else if (mount_mode == MOUNT_EXTERNAL_READ) {
        storageSource = "/mnt/runtime/read";
    } else if (mount_mode == MOUNT_EXTERNAL_WRITE) {
        storageSource = "/mnt/runtime/write";
    } else if (!force_mount_namespace) {
        // Sane default of no storage visible
        return true;
    }
    ...
}

所以如果应用没有申请WRITE_EXTERNAL_STORAGE权限,/sdcard指向的是/mnt/runtime/default。经测试,如果始终使用"/mnt/runtime/write",则文件可写。

但是/mnt/runtime/default/emulated/0文件夹属于用户组sdcard_rw,用户u0_a45属于该用户组。在命令行的实测,u0_a45确实可以在该目录创建文件。这说明Android可能有其他的措施禁止应用写文件。

127|angler:/mnt/runtime/default/emulated/0 $ whoami
u0_a45
angler:/mnt/runtime/default/emulated/0 $ ls -l
total 40
drwxrwx--x 2 root sdcard_rw 4096 1970-04-24 13:27 Alarms
drwxrwx--x 3 root sdcard_rw 4096 1970-04-24 13:27 Android
drwxrwx--x 2 root sdcard_rw 4096 1970-04-24 13:27 DCIM
drwxrwx--x 2 root sdcard_rw 4096 1970-04-24 13:27 Download
drwxrwx--x 2 root sdcard_rw 4096 1970-04-24 13:27 Movies
drwxrwx--x 2 root sdcard_rw 4096 1970-04-24 13:27 Music
drwxrwx--x 2 root sdcard_rw 4096 1970-04-24 13:27 Notifications
drwxrwx--x 2 root sdcard_rw 4096 1970-04-24 13:27 Pictures
drwxrwx--x 2 root sdcard_rw 4096 1970-04-24 13:27 Podcasts
drwxrwx--x 2 root sdcard_rw 4096 1970-04-24 13:27 Ringtones
angler:/mnt/runtime/default/emulated/0 $ touch test
angler:/mnt/runtime/default/emulated/0 $ ls -l                                                                                                                                                                    
total 40
drwxrwx--x 2 root sdcard_rw 4096 1970-04-24 13:27 Alarms
drwxrwx--x 3 root sdcard_rw 4096 1970-04-24 13:27 Android
drwxrwx--x 2 root sdcard_rw 4096 1970-04-24 13:27 DCIM
drwxrwx--x 2 root sdcard_rw 4096 1970-04-24 13:27 Download
drwxrwx--x 2 root sdcard_rw 4096 1970-04-24 13:27 Movies
drwxrwx--x 2 root sdcard_rw 4096 1970-04-24 13:27 Music
drwxrwx--x 2 root sdcard_rw 4096 1970-04-24 13:27 Notifications
drwxrwx--x 2 root sdcard_rw 4096 1970-04-24 13:27 Pictures
drwxrwx--x 2 root sdcard_rw 4096 1970-04-24 13:27 Podcasts
drwxrwx--x 2 root sdcard_rw 4096 1970-04-24 13:27 Ringtones
-rw-rw---- 1 root sdcard_rw    0 1970-04-24 13:34 test

在adb shell里面,用ps查看pid,然后进入/proc/ # cat status
Name: e.myapplication
State: S (sleeping)
Tgid: 8272
Pid: 8272
PPid: 619
TracerPid: 0
Uid: 10063 10063 10063 10063
Gid: 10063 10063 10063 10063
FDSize: 128
Groups: 9997 20063 50063

如果应用没有声明WRITE_EXTERNAL_STORAGE,则应用用户不属于sdcard_rw组。如果应用声明了WRITE_EXTERNAL_STORAGE,则属于Groups行会有1015,即sdcard_rw的gid。但是,即使应用声明了WRITE_EXTERNAL_STORAGE,如果用户没有授予此权限,应用仍然不可创建文件。这一层逻辑是在哪里呢?