使用 run-as 命令在 ADB shell 中复制文件

16
有没有办法编写脚本,使用run-as从ADB shell复制文件?我所知道的唯一在adb shell中复制的方法是使用“cat source > dest”(编辑:现代Android版本具有“cp”命令,这使得此问题不必要),但我只能引用大于号一级深度 - 所以我的脚本可以将其传递给adb shell,但不能传递给adb shell run-as。例如,这个有效:adb shell "cat source > dest",但这个无效:adb shell run-as "cat source > dest",也不是这个:adb shell "run-as cat source \> dest"。我甚至尝试创建一个小脚本并将其上传到设备上,但我似乎无法从adb shell运行该脚本 - 它告诉我“权限被拒绝”。我也无法对脚本进行chmod。我想做的原因是将文件复制到应用程序的私有存储区域 - 具体来说,我正在使用脚本修改共享首选项并将修改后的首选项放回。然而,只有应用程序本身或root才能写入我想要的文件。
在这种情况下的用例是将文件复制到设备上受保护的位置,而不是检索它;对于检索,此问题中已经有了很好的答案。

很可能您无法执行上传的脚本,因为外部存储已挂载noexec标志。如果将其放入应用程序的私有存储或/data下的某个tmp目录中,则应该能够使其可执行。但是,将导出功能构建到(调试版本的)应用程序中,以此方式进行复制如何?另一个选项是从类似于“echo”的东西中pipe命令进入adb shell run-as com.foo.bar会话。 - Chris Stratton
你可以让应用程序编写脚本或给你写入目录的权限。 - Chris Stratton
1
顺便提一下,如果你使用的是最新版本的Android系统,它现在已经有了一个cp命令。 - Chris Stratton
@ChrisStratton 一种变体的管道方法起作用了。请将此作为答案发布,以便我可以接受它并详细说明对我有用的内容! - Logan Pickup
Logan,你觉得直接把你成功的那个方案发出来怎么样?因为我上周五做的管道试验效果并不好。 - Chris Stratton
显示剩余8条评论
4个回答

22

这位OP试图将以下3个命令(在交互式shell会话中一个接一个地执行没有问题)组合成单个非交互式命令:

adb shell
run-as com.example.app
cat /sdcard/temp_prefs.xml > shared_prefs/com.example.app_preferences.xml

为了简单起见,让我们从一个交互式的adb shell会话中开始。如果我们试图将最后两个命令组合成一行:

为了方便起见,让我们从一个交互式的adb shell会话开始。如果我们尝试将最后两个命令合并成一行:

run-as com.example.app cat /sdcard/temp_prefs.xml > shared_prefs/com.example.app_preferences.xml

由于shell重定向的工作原理,这种方式行不通 - 命令中只有cat /sdcard/temp_prefs.xml部分会以com.example.app UID执行

许多人“知道”将重定向周围的命令部分加上引号:

run-as com.example.app "cat /sdcard/temp_prefs.xml > shared_prefs/com.example.app_preferences.xml"

这样做不起作用是因为run-as命令不够智能,无法解析整个命令。它期望下一个参数是可执行文件。正确的方法是改用sh

run-as com.example.app sh -c "cat /sdcard/temp_prefs.xml > shared_prefs/com.example.app_preferences.xml"

那我们只需在命令前加上adb shell就可以了吗?并不是。从PC运行命令还会添加另一个本地shell及其解析器。特定的转义要求取决于您的操作系统。在Linux或OSX中(如果您的命令不包含任何'),可以很容易地用单引号括起整个命令,如下所示:

adb shell 'run-as com.example.app sh -c "cat /sdcard/temp_prefs.xml > shared_prefs/com.example.app_preferences.xml"'

但有时使用替代解决方案更容易,带有(-out 或较少的)引号:

adb shell run-as com.example.app cp /sdcard/temp_prefs.xml shared_prefs/com.example.app_preferences.xml

或者,如果您的设备没有cp命令:

adb shell run-as com.example.app dd if=/sdcard/temp_prefs.xml of=shared_prefs/com.example.app_preferences.xml

请注意我使用的是 shared_prefs/com.example.app_preferences.xml 而不是完整路径 /data/data/com.example.app/shared_prefs/com.example.app_preferences.xml - 通常在 run-as 命令中,您当前所在的目录是您的包的 Home 目录。


我认为这仅适用于设备上只有一个配置文件的情况,因为它将作为用户0运行,这意味着它不适用于工作/企业/辅助配置文件。 - Chapz

13

按照Chris Stratton的建议,最终让我成功的方法是这样的(将共享首选项复制回设备):

adb push shared_prefs.xml /sdcard/temp_prefs.xml
cat <<EOF | adb shell
run-as com.example.app
cat /sdcard/temp_prefs.xml > /data/data/com.example.app/shared_prefs/com.example.app_preferences.xml
exit
exit
EOF
直接将数据通过管道传输到adb shell run-as是不能正常工作的,我不知道为什么,但是通过管道传输到adb shell可以。关键是从交互式shell中调用run-as,并且它仍然从管道接受输入。
使用HERE doc让我可以轻松地嵌入换行符以分隔命令,并且通常使其易读;我没有尝试过分号,但那可能是因为我当时的方式不对。我相信这可能适用于通过其他方法传输多个命令/换行符的情况;一旦我终于让它工作了,就停止了实验。
两个退出命令都是必要的,以防止出现挂起的shell(可以通过CTRL-C终止);一个是给run-as,另一个是给adb shell本身。似乎Adb的shell对文件末尾并不会作出良好的反应。

做得好,找出了让它工作的方法。我的错误在于尝试管道输入到 adb shell run-as,这显然表现不同。 - Chris Stratton
@ChrisStratton 我一开始也尝试过那种方式。只有在我弄清楚它能够成功传递到 adb shell 后,我才想到用这种方式来做。 - Logan Pickup

3

您可以更改目录的权限,然后提取所有文件。但对于我来说,我只是在寻找一个共享首选项文件,并且我能够像这样获取数据:

PACKAGE='com.mypackage.cool'
SHAREDPREF_FILE="${PACKAGE}_preferences.xml"

    adb shell "run-as $PACKAGE cat /data/data/$PACKAGE/shared_prefs/$SHAREDPREF_FILE">$SHAREDPREF_FILE

现在我们已经将SharedPreference文件中的数据存储在同名文件中。

0

使用最新的adb(ADB v1.0.41 / 版本33.0.3)和Play Store模拟器映像时,我遇到了未被授权的adb root。当run-as com.myapp.app时,我也无法从/data/local//storage/emulated/0/复制文件,因为没有权限。

new_prefs_path="my_machine.xml"
config="$(cat $new_prefs_path)"
my_app_uri="com.myapp.app"
adb shell "run-as $my_app_uri sh -c 'echo \"$config\" > shared_prefs/on_android.xml'"

以下是我使用Bash脚本修复它的方法。由于需要为不同的应用程序和复杂的有效负载进行配置,稍微复杂了一些。 我们获取一个文件(可以在此脚本中先生成),并将其读取到变量中。 然后启动shell,执行run-as我的应用程序,并运行echo将读取的文件扩展到shared_prefs中的一个文件。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接