android 读写权限单独控制
前言
最近有一个需求,需要从手机端这边单独控制手机的读写权限,也就是adb 的pull 和push 权限,MTP 文件管理的copy delet 等操作。
禁止或允许adb 和MTP 的方法我知道。从插上usb 线弹出的那个选择框的源码入手,就可以看到。设置个参数就可以了。方法如下:
private final static int ADB_DISABLE_ALL = 0;
private final static int ADB_ENABLE_ADB = 1;
private final static int ADB_ENABLE_MTP = 2;
Settings.Global.putInt(getContext().getContentResolver(), "usb_per_settings", ADB_DISABLE_ALL);
但是分别控制,那肯定就得改这两个实现的源码了。首先来看下ADB
分析
要对adb 的push 和pull 命令来客制化。那肯定是要找他们实现的地方了。因为这块代码我也没接触过。但是我手里有系统源码。
就和解决大多数问题一样,通过log 来搜索具体代码实现。我敲adb 命令时,命令端会回复,那么我就尝试搜回复的字段来确定adb 的源码。如下,当我在"PC"端输入adb 时,会刷出如下的help 信息,以及我通过adb push,pull 时,也会一些提示信息。
PS C:\Users\xxx> adb
Android Debug Bridge version 1.0.41
Version 30.0.3-6597393
Installed as E:\android-sdk_r24.4.1-windows\android-sdk-windows\platform-tools\adb.exe
global options:
-a listen on all network interfaces, not just localhost
-d use USB device (error if multiple devices connected)
-e use TCP/IP device (error if multiple TCP/IP devices available)
-s SERIAL use device with given serial (overrides $ANDROID_SERIAL)
-t ID use device with given transport id
-H name of adb server host [default=localhost]
-P port of adb server [default=5037]
-L SOCKET listen on given socket for adb server [default=tcp:localhost:5037]
general commands:
devices [-l] list connected devices (-l for long output)
help show this help message
version show version num
networking:
connect HOST[:PORT] connect to a device via TCP/IP [default port=5555]
disconnect [HOST[:PORT]]
disconnect from given TCP/IP device [default port=5555], or all
pair HOST[:PORT] [PAIRING CODE]
pair with a device for secure TCP/IP communication
forward --list list all forward socket connections
forward [--no-rebind] LOCAL REMOTE
forward socket connection using:
tcp:<port> (<local> may be "tcp:0" to pick any open port)
localabstract:<unix domain socket name>
localreserved:<unix domain socket name>
localfilesystem:<unix domain socket name>
dev:<character device name>
jdwp:<process pid> (remote only)
acceptfd:<fd> (listen only)
forward --remove LOCAL remove specific forward socket connection
forward --remove-all remove all forward socket connections
ppp TTY [PARAMETER...] run PPP over USB
reverse --list list all reverse socket connections from device
reverse [--no-rebind] REMOTE LOCAL
reverse socket connection using:
tcp:<port> (<remote> may be "tcp:0" to pick any open port)
localabstract:<unix domain socket name>
localreserved:<unix domain socket name>
localfilesystem:<unix domain socket name>
reverse --remove REMOTE remove specific reverse socket connection
reverse --remove-all remove all reverse socket connections from device
mdns check check if mdns discovery is available
mdns services list all discovered services
file transfer:
push [--sync] [-z ALGORITHM] [-Z] LOCAL... REMOTE
copy local files/directories to device
--sync: only push files that are newer on the host than the device
-n: dry run: push files to device without storing to the filesystem
-z: enable compression with a specified algorithm (any, none, brotli)
-Z: disable compression
pull [-a] [-z ALGORITHM] [-Z] REMOTE... LOCAL
copy files/dirs from device
-a: preserve file timestamp and mode
-z: enable compression with a specified algorithm (any, none, brotli)
-Z: disable compression
sync [-l] [-z ALGORITHM] [-Z] [all|data|odm|oem|product|system|system_ext|vendor]
sync a local build from $ANDROID_PRODUCT_OUT to the device (default all)
-n: dry run: push files to device without storing to the filesystem
-l: list files that would be copied, but don't copy them
-z: enable compression with a specified algorithm (any, none, brotli)
-Z: disable compression
shell:
shell [-e ESCAPE] [-n] [-Tt] [-x] [COMMAND...]
run remote shell command (interactive shell if no command given)
-e: choose escape character, or "none"; default '~'
-n: don't read from stdin
-T: disable pty allocation
-t: allocate a pty if on a tty (-tt: force pty allocation)
-x: disable remote exit codes and stdout/stderr separation
emu COMMAND run emulator console command
app installation (see also `adb shell cmd package help`):
install [-lrtsdg] [--instant] PACKAGE
push a single package to the device and install it
install-multiple [-lrtsdpg] [--instant] PACKAGE...
push multiple APKs to the device for a single package and install them
install-multi-package [-lrtsdpg] [--instant] PACKAGE...
push one or more packages to the device and install them atomically
-r: replace existing application
-t: allow test packages
-d: allow version code downgrade (debuggable packages only)
-p: partial application install (install-multiple only)
-g: grant all runtime permissions
--abi ABI: override platform's default ABI
--instant: cause the app to be installed as an ephemeral install app
--no-streaming: always push APK to device and invoke Package Manager as separate steps
--streaming: force streaming APK directly into Package Manager
--fastdeploy: use fast deploy
--no-fastdeploy: prevent use of fast deploy
--force-agent: force update of deployment agent when using fast deploy
--date-check-agent: update deployment agent when local version is newer and using fast deploy
--version-check-agent: update deployment agent when local version has different version code and using fast deploy
(See also `adb shell pm help` for more options.)
uninstall [-k] PACKAGE
remove this app package from the device
'-k': keep the data and cache directories
debugging:
bugreport [PATH]
write bugreport to given PATH [default=bugreport.zip];
if PATH is a directory, the bug report is saved in that directory.
devices that don't support zipped bug reports output to stdout.
jdwp list pids of processes hosting a JDWP transport
logcat show device log (logcat --help for more)
security:
disable-verity disable dm-verity checking on userdebug builds
enable-verity re-enable dm-verity checking on userdebug builds
keygen FILE
generate adb public/private key; private key stored in FILE,
scripting:
wait-for[-TRANSPORT]-STATE...
wait for device to be in a given state
STATE: device, recovery, rescue, sideload, bootloader, or disconnect
TRANSPORT: usb, local, or any [default=any]
get-state print offline | bootloader | device
get-serialno print <serial-number>
get-devpath print <device-path>
remount [-R]
remount partitions read-write. if a reboot is required, -R will
will automatically reboot the device.
reboot [bootloader|recovery|sideload|sideload-auto-reboot]
reboot the device; defaults to booting system image but
supports bootloader and recovery too. sideload reboots
into recovery and automatically starts sideload mode,
sideload-auto-reboot is the same but reboots after sideloading.
sideload OTAPACKAGE sideload the given full OTA package
root restart adbd with root permissions
unroot restart adbd without root permissions
usb restart adbd listening on USB
tcpip PORT restart adbd listening on TCP on PORT
internal debugging:
start-server ensure that there is a server running
kill-server kill the server if it is running
reconnect kick connection from host side to force reconnect
reconnect device kick connection from device side to force reconnect
reconnect offline reset offline/unauthorized devices to force reconnect
environment variables:
$ADB_TRACE
comma-separated list of debug info to log:
all,adb,sockets,packets,rwx,usb,sync,sysdeps,transport,jdwp
$ADB_VENDOR_KEYS colon-separated list of keys (files or directories)
$ANDROID_SERIAL serial number to connect to (see -s)
$ANDROID_LOG_TAGS tags to be used by logcat (see logcat --help)
$ADB_LOCAL_TRANSPORT_MAX_PORT max emulator scan port (default 5585, 16 emus)
$ADB_MDNS_AUTO_CONNECT comma-separated list of mdns services to allow auto-connect (default adb-tls-connect)
PS C:\Users\xxx> adb pull
adb.exe: pull requires an argument
PS C:\Users\xxx> adb push
adb.exe: push requires an argument
PS C:\Users\xxx>
这样我搜了之后。然后按照我的思路(通过在上层设置不同的prop 来控制adb 是否push 或者pull)。如下:
按照正常的逻辑,我加入的打印,应该可以正常的打印出来。可是就是不生效。最后。我才发现,我犯了一个致命的错误。我找到的这个文件,是PC 端的。因为我的需求是要在手机端去控制。我修改了PC 端adb 逻辑,肯定体现不到手机端上去啊。最后我在网上搜了下。
adb 的实现都是在 system/core/adb下。
adb PC 端的实现是在 system/core/adb/client
adb 手机端的实现是在 system/core/adb/daemon
实现
于是在 daemon 下查找手机端的pull 和push 的命令。
/system/core/adb/file_sync_service.cpp
static bool handle_sync_command(int fd, std::vector<char>& buffer) { // 此方法是处理adb 命令的。
470 D("sync: waiting for request");
471
472 ATRACE_CALL();
473 SyncRequest request;
474 if (!ReadFdExactly(fd, &request, sizeof(request))) {
475 SendSyncFail(fd, "command read failure");
476 return false;
477 }
478 size_t path_length = request.path_length;
479 if (path_length > 1024) {
480 SendSyncFail(fd, "path too long");
481 return false;
482 }
483 char name[1025];
484 if (!ReadFdExactly(fd, name, path_length)) {
485 SendSyncFail(fd, "filename read failure");
486 return false;
487 }
488 name[path_length] = 0;
489
490 std::string id_name = sync_id_to_name(request.id);
491 std::string trace_name = StringPrintf("%s(%s)", id_name.c_str(), name);
492 ATRACE_NAME(trace_name.c_str());
493
494 D("sync: %s('%s')", id_name.c_str(), name);
495 switch (request.id) {
496 case ID_LSTAT_V1:
497 if (!do_lstat_v1(fd, name)) return false;
498 break;
499 case ID_LSTAT_V2:
500 case ID_STAT_V2:
501 if (!do_stat_v2(fd, request.id, name)) return false;
502 break;
503 case ID_LIST:
504 if (!do_list(fd, name)) return false;
505 break;
506 case ID_SEND:
507 if (!do_send(fd, name, buffer)) return false;
508 break;
509 case ID_RECV:
510 if (!do_recv(fd, name, buffer)) return false;
511 break;
512 case ID_QUIT:
513 return false;
514 default:
515 SendSyncFail(fd, StringPrintf("unknown command %08x", request.id));
516 return false;
517 }
518
519 return true;
520}
接下来,在上面case 里面加log 打印:
最后打印如下:
此时,则可以知道。adb 的push 和pull 的具体实现逻辑。这时候只要加上prop 的判断条件即可。