I'm using adb to sync music on an android phone. Essentially, I rm the existing music directory and push replacement music files.
I'd like to be able to use adb to force a rescan, so that the google music player (and other apps) works properly with the new songs and playlists.
According to How can I refresh MediaStore on Android? you can force a rescan by broadcasting an appropriate intent.
adb provides 'shell am broadcast', which would seem to allow me to force a rescan from adb.
Alternatively I could run a rescan app or reboot, but I'd like to trigger the rescan from adb
What adb command should I issue? The music files and playlists are all in /sdcard/music.
The rescan apps use a media mount intent to kick off the media scanner. You can use am broadcast to send the same intent.
The command is:
adb shell am broadcast -a android.intent.action.MEDIA_MOUNTED -d file:///sdcard
The MEDIA_MOUNTED intent is no longer permitted (post KitKat) for non-system apps; try this instead.
It’s not recursive, though, and has to be run on the exact_file_name, so it’s not a good replacement.
adb shell am broadcast \
-a android.intent.action.MEDIA_SCANNER_SCAN_FILE \
-d file:///mnt/sdcard/Music/<exact_file_name>
If you need to rescan recursively, you can use this command (fix paths accordingly):
adb shell "find /mnt/sdcard/Music/ -exec am broadcast \
-a android.intent.action.MEDIA_SCANNER_SCAN_FILE \
-d file://{} \\;"
Or like this (if above won't work for you):
adb shell "find /mnt/sdcard/Music/ | while read f; do \
am broadcast -a android.intent.action.MEDIA_SCANNER_SCAN_FILE \
-d \"file://${f}\"; done"
On some Samsung mobiles, you can get a full rescan like this:
am broadcast -a com.samsung.intent.action.MTP_FILE_SCAN -n com.android.providers.media/.MediaScannerReceiver
If you have rooted your phone, you can use this script I’ve written, which has the advantage of keeping track of which files have already been updated:
#!/system/bin/env busybox ash
MUSIC_LIBRARY=/sdcard/MusicLibrary
LAST_UPDATE="$(stat -c %Y "$MUSIC_LIBRARY/.last-update")"
find "$MUSIC_LIBRARY" -type f ! -iname ".last-update" | (
while read f; do
if ! test "$LAST_UPDATE" -ge "$(stat -c %Y "$f")"; then
am broadcast -a android.intent.action.MEDIA_SCANNER_SCAN_FILE -d "file://$f"
touch "$f"
else
echo "Not updated: \`$f'"
fi
done
)
touch "$MUSIC_LIBRARY/.last-update"
Here's a Python script called adb-scan.
It uses adb to ask the Android device to rescan the given files.
Example usage:
$ adb-scan Notifications/\*.mp3
Broadcasting: Intent { act=android.intent.action.MEDIA_SCANNER_SCAN_FILE dat=file:///sdcard/Notifications/cough.mp3 flg=0x400000 }
Broadcast completed: result=0
Broadcasting: Intent { act=android.intent.action.MEDIA_SCANNER_SCAN_FILE dat=file:///sdcard/Notifications/harmonica3.mp3 flg=0x400000 }
Broadcast completed: result=0
Broadcasting: Intent { act=android.intent.action.MEDIA_SCANNER_SCAN_FILE dat=file:///sdcard/Notifications/shhh.mp3 flg=0x400000 }
Broadcast completed: result=0
$
Here's the script:
#!/usr/bin/python3
#
# Ask the Android media scanner to check the given files.
#
import sys
import os
import re
sys.argv.pop(0)
if not sys.argv:
sys.exit('usage: adb-scan files...')
intent = 'android.intent.action.MEDIA_SCANNER_SCAN_FILE'
# Quote certain special characters such as spaces, backslashes and quotes. In
# particular, don't quote '*' because we want that to be expanded on the
# Android device.
def cleanup(arg):
if not arg.startswith('/'):
arg = '/sdcard/' + arg
arg = re.sub("[ \\'\"]", lambda x: '\\' + x.group(0), arg)
return arg
script = '''
for i in {args}; do
[ -e "$i" ] || echo "warning: no such file: $i"
am broadcast -a "{intent}" -d "file://$i"
done
'''.format(args=' '.join(map(cleanup, sys.argv)),
intent=intent)
cmd = ['adb', 'shell', script]
os.execvp(cmd[0], cmd)
Related
I need to specifically use Windows 10 Powershell, not gitbash or cygwin or CMD, as other answers on SO have provided. I need to be able to use wildcards. I need to be able to push from Windows to Android to a specific folder using wildcards (not entire folder at a time as other answers on SO have provided).
Ex: adb push *.png /sdcard/Android/data/myapp/files
Ex: adb pull /sdcard/Android/data/myapp/files/h*.txt
Apologies if this has been answered, I have yet to find this specific answer.
You can leverage loops in powershell to call adb command separately for each file. Get the files you want to push or pull, loop through and call adb for each.
$adb = 'C:\temp\platform-tools\adb.exe'
$local = 'C:\temp\testfiles'
$remote = '/sdcard/Android/data/myapp/files'
function push-adbfiles {
param ()
# use Get-ChildItem to capture which files to push
$files = Get-ChildItem -file $local\*.png
# loop using ForEach-Object and call adb push command for each
$files | ForEach-Object {
& $adb push $_ $remote
}
}
function pull-adbfiles {
param ()
# use nix find command to find and return full path of matching files
$files = & $adb shell find "$remote/h*"
# loop through files running adb pull on each
$files | ForEach-Object {
& $adb pull $_ $local
}
}
I'm developing an application that uses ADB Shell to interface with android devices, and I need some way of printing out the application name or label of an application, given maybe their package name.
In short, I need a way of getting app names (i.e. "Angry Birds v1.0.0") for user installed applications through adb shell.
Any light on the matter? Any help is appreciated on this.
adb shell pm list packages will give you a list of all installed package names.
You can then use dumpsys | grep -A18 "Package \[my.package\]" to grab the package information such as version identifiers etc
just enter the following command on command prompt after launching the app:
adb shell dumpsys window windows | find "mCurrentFocus"
if executing the command on linux terminal replace find by grep
If you know the app id of the package (like org.mozilla.firefox), it is easy.
First to get the path of actual package file of the appId,
$ adb shell pm list packages -f com.google.android.apps.inbox
package:/data/app/com.google.android.apps.inbox-1/base.apk=com.google.android.apps.inbox
Now you can do some grep|sed magic to extract the path : /data/app/com.google.android.apps.inbox-1/base.apk
After that aapt tool comes in handy :
$ adb shell aapt dump badging /data/app/com.google.android.apps.inbox-1/base.apk
...
application-label:'Inbox'
application-label-hi:'Inbox'
application-label-ru:'Inbox'
...
Again some grep magic to get the Label.
A shell script to accomplish this:
#!/bin/bash
# Remove whitespace
function remWS {
if [ -z "${1}" ]; then
cat | tr -d '[:space:]'
else
echo "${1}" | tr -d '[:space:]'
fi
}
for pkg in $(adb shell pm list packages -3 | cut -d':' -f2); do
apk_loc="$(adb shell pm path $(remWS $pkg) | cut -d':' -f2 | remWS)"
apk_name="$(adb shell aapt dump badging $apk_loc | pcregrep -o1 $'application-label:\'(.+)\'' | remWS)"
apk_info="$(adb shell aapt dump badging $apk_loc | pcregrep -o1 '\b(package: .+)')"
echo "$apk_name v$(echo $apk_info | pcregrep -io1 -e $'\\bversionName=\'(.+?)\'')"
done
Inorder to find an app's name (application label), you need to do the following:
(as shown in other answers)
Find the APK path of the app whose name you want to find.
Using aapt command, find the app label.
But devices don't ship with the aapt binary out-of-the-box.
So you will need to install it first. You can download it from here:
https://github.com/Calsign/APDE/tree/master/APDE/src/main/assets/aapt-binaries
Check this guide for complete steps:
How to find an app name using package name through ADB Android?
(Disclaimer: I am the author of that blog post)
This is what I just came up with. It gives a few errors but works well enough for my needs, matching package names to labels.
It pulls copies of all packages into subdirectories of $PWD, so keep that in mind if storage is a concern.
#!/bin/bash
TOOLS=~/Downloads/adt-bundle-linux-x86_64-20130717/sdk/build-tools/19.1.0
AAPT=$TOOLS/aapt
PMLIST=adb_shell_pm_list_packages_-f.txt
TEMP=$(echo $(adb shell mktemp -d -p /data/local/tmp) | sed 's/\r//')
mkdir -p packages
[ -f $PMLIST ] || eval $(echo $(basename $PMLIST) | tr '_' ' ') > $PMLIST
while read line; do
package=${line##*:}
apk=${package%%=*}
name=${package#*=}
copy=packages$apk
mkdir -p $(dirname $copy)
if [ ! -s $copy ]; then # copy it because `adb pull` doesn't see /mnt/expand/
adb shell cp -f $apk $TEMP/copy.apk
adb pull $TEMP/copy.apk $copy
fi
label=$($AAPT dump badging $copy || echo ERROR in $copy >&2 | \
sed -n 's/^application-label:\(.\)\(.*\)\1$/\2/p')
echo $name:$label
done < <(sed 's/\r//' $PMLIST)
adb shell rm -rf $TEMP
So I extremely grateful to jcomeau_ictx for providing the info on how to extract application-label info from apk and the idea to pull apk from phone directly!
However I had to make several alteration to script it self:
while read line; do done are breaking as a result of commands within while loop interacting with stdin/stdout and as a result while loop runs only once and then stops, as it is discussed in While loop stops reading after the first line in Bash - the comment from cmo I used solution provided and switched while loop to use unused file descriptor number 9.
All that the script really need is a package name and adb shell pm list packages -f is really excessive so I changed it to expect a file with packages list only and provided example on how one can get one from adb.
jcomeau_ictx script variant do not take in to account that some packages may have multiple apk associated with them which breaks the script.
And the least and last, I made every variable to start with underscore, it's just something that makes it easier to read script.
So here another variant of the same script:
#!/bin/bash
_TOOLS=/opt/android-sdk-update-manager/build-tools/29.0.3
_AAPT=${_TOOLS}/aapt
#adb shell pm list packages --user 0 | sed -e 's|^package:||' | sort >./packages_list.txt
_PMLIST=packages_list.txt
rm ./packages_list_with_names.txt
_TEMP=$(echo $(adb shell mktemp -d -p /data/local/tmp) | sed 's/\r//')
mkdir -p packages
[ -f ${_PMLIST} ] || eval $(echo $(basename ${_PMLIST}) | tr '_' ' ') > ${_PMLIST}
while read -u 9 _line; do
_package=${_line##*:}
_apkpath=$(adb shell pm path ${_package} | sed -e 's|^package:||' | head -n 1)
_apkfilename=$(basename "${_apkpath}")
adb shell cp -f ${_apkpath} ${_TEMP}/copy.apk
adb pull ${_TEMP}/copy.apk ./packages
_name=$(${_AAPT} dump badging ./packages/copy.apk | sed -n 's|^application-label:\(.\)\(.*\)\1$|\2|p' )
#'
echo "${_package} - ${_name}" >>./packages_list_with_names.txt
done 9< ${_PMLIST}
adb shell rm -rf $TEMP
I am working on one project requires obtaining the complete app package name inside kernel mode. I realized the package name is also the process name inside kernel. However, the task_struct->comm (process name) can only give me 15 characters long.
Also, fs/proc/base.c proc_get_cmdline() can return the full process name but it is private function. I try to export proc_get_cmdline() to public and invoke from my loadable kernel module, but it always crash when I invoke the public proc_get_cmdline().
Is there any way I can get the complete package name inside kernel? Like read from proc/pid/cmdline, read from mm_struct, etc. Appreciate any code example.
You are not supposed to call proc_pid_cmdline().
It is a non-public function in fs/proc/base.c:
static int proc_pid_cmdline(struct seq_file *m, struct pid_namespace *ns,
struct pid *pid, struct task_struct *task)
However, what it does is simple:
get_cmdline(task, m->buf, PAGE_SIZE);
That is not likely to return the full path though and it will not be possible to determine the full path in every case. The arg[0] value may be overwritten, the file could be deleted or moved, etc. A process may exec() in a way which obscures the original command line, and all kinds of other maladies.
A scan of my opensuse 12.3 system /proc/*/cmdline turns up all kinds of less-than-useful results:
/proc/1/cmdline
/sbin/init showopts
/proc/10/cmdline
/proc/11/cmdline
/proc/1163/cmdline
/sbin/dhclient6 -6 -cf /var/lib/dhcp6/dhclient6.eth0.conf -lf /var/lib/dhcp6/dhclient6.eth0.lease -pf /var/run/dhclient6.eth0.pid -q eth0
/proc/12/cmdline
/proc/13/cmdline
/proc/14/cmdline
/proc/15/cmdline
/proc/16/cmdline
/proc/17/cmdline
/proc/1710/cmdline
/sbin/dhcpcd --netconfig -L -E -HHH -c /etc/sysconfig/network/scripts/dhcpcd-hook -t 0 -h del1-dhp-32429 eth0
/proc/172/cmdline
/proc/185/cmdline
/proc/186/cmdline
/proc/187/cmdline
/proc/19/cmdline
/proc/2/cmdline
/proc/20/cmdline
/proc/21/cmdline
/proc/22/cmdline
/proc/23/cmdline
/proc/25/cmdline
/proc/254/cmdline
/proc/255/cmdline
/proc/26/cmdline
/proc/2671/cmdline
/usr/lib/upower/upowerd
/proc/2674/cmdline
/usr/lib/polkit-1/polkitd --no-debug
/proc/27/cmdline
/proc/2727/cmdline
/usr/lib/udisks2/udisksd --no-debug
/proc/28/cmdline
/proc/285/cmdline
/usr/lib/systemd/systemd-journald
/proc/286/cmdline
/proc/288/cmdline
/proc/29/cmdline
/proc/2913/cmdline
/usr/sbin/cron -n
/proc/2924/cmdline
/usr/sbin/sshd -D
/proc/3/cmdline
/proc/3023/cmdline
/usr/lib/postfix/master
/proc/3090/cmdline
pickup -l -t fifo -u
/proc/3091/cmdline
qmgr -l -t fifo -u
/proc/31/cmdline
/proc/311/cmdline
/usr/lib/systemd/systemd-udevd
/proc/3132/cmdline
/usr/lib/vmware/bin/vmware-vmblock-fuse -o subtype=vmware-vmblock,default_permissions,allow_other /var/run/vmblock-fuse
/proc/3168/cmdline
/usr/sbin/vmware-authdlauncher
/proc/32/cmdline
Works for me in openSUSE 12.3:
for I in /proc/*/cmdline; do echo $I; cat $I | tr '\000' ' '; echo; done
I'm trying to write an android app that backs up data from selected directory of an android device to a remote host using rsync and ssh. When I run the rsync command from adb shell as follows, it works:
rsync -rvz -e "/system/xbin/ssh -y -p 22" "/mnt/sdcard/" "rajeesh#10.0.2.2:backup/"
But my java code using Runtime.exec fails with an error that says:
Error: rsync: failed to exec /system/xbin/ssh -y -p 22: No such file or directory (2)
The code I used is as follows:
String[] commands = {
"rsync", "-rvz", "-e", "\"/system/xbin/ssh -y -p 22\"",
"\"/mnt/sdcard/\"", "\"rajeesh#10.0.2.2:backup/\""
};
Process process = Runtime.getRuntime().exec(commands);
Both rsync and ssh have been placed at /system/xbin and chmoded to 755. Tried replacing "rsync" with "/system/xbin/rsync" also but the issue remains. What would be the issue here?
Found out the issue myself.
When run directly from the shell, quotes have specific meaning and they are required here as follows:
rsync -rvz -e "ssh -y -p 22" "/path/to/src/" "/path/to/dest"
My java snippet above was trying to run the command with the quotes escaped, like "\"arg\"". But quotes not required when used outside shell. The correct usage is:
String[] commands = {
"/system/xbin/rsync", "-rvz", "-e", "/system/xbin/ssh -y -p 22",
"/mnt/sdcard", "rajeesh#10.0.2.2:backup/"
};
I'm not sure but maybe problem is that the destination path (rajeesh#10.0.2.2:backup/) is not absolute?
Also if you what to sync your files in the same device, maybe you should try to not use ssh? And do something like that:
rsync -rvz /mnt/sdcard/some_directory /backup
The Logcat in Eclipse has colors for errors, warning, debug, ...
How can I do to get the same result on Linux (Ubuntu) when I run the command 'adb -e logcat' in a terminal to get it colored?
adb logcat -v color
from developer.android.com
Link with script
I think it will be useful for you and you can change script by yourself;)
This is my view of "colorizing" the logcat:
https://bitbucket.org/brunobraga/logcat-colorize
My favourite is pidcat, maintained by Jake Wharton based off of Jeff Sharkey's script (mentioned by Yaroslav Boichuk).
I have also used logcat-color, maintained by Marshall Culpepper, (also based off of Jeff's script) which allows you to create profiles you can activate (log per task, or per application, etc).
I have preferred pidcat because at the time logcat-color wouldn't filter by package name, and I never went back to try again once it was added. Seems to be reasonably popular still as well.
And yet another script:
#!/bin/sh
while :; do
adb $# logcat | sed \
-e 's:^V/:\x00\x1b[0;35m:g' \
-e 's:^D/:\x00\x1b[0;36m:g' \
-e 's:^I/:\x00\x1b[0;32m:g' \
-e 's:^W/:\x00\x1b[0;33m:g' \
-e 's:^E/:\x00\x1b[0;31m:g' \
-e 's:^F/:\x00\x1b[0;31m:g' \
-e '/Unexpected value from nativeGetEnabledTags/d' \
-e '/The application may be/d'
sleep 1
done
If you use Python, PyLogAnalyser can filter, colorize and analyse all type of logs in Linux, Windows and Mac (and Cygwin).
You can install it directly from PyPI:
python -m pip install pyloganalyser
And call it in order to print the log for the standard output (also, for text or HTML output):
adb logcat -v threadtime | python -m loganalyser --stdin --stdout -c Android_logcat_threadtime.conf
The file 'Android_logcat_threadtime.conf' is included in the module directory. So the actual invocation could be:
CONFPATH="$(python -c 'import loganalyser;print loganalyser.__file__.replace("/__init__.pyc","")')";
adb logcat -v threadtime | python -m loganalyser --stdin --stdout -c "$CONFPATH"/android/Android_logcat_threadtime.conf
Website: http://pyloganalyser.sourceforge.net
Have a try with lnav , add logcat config from here