├── .gitignore ├── .travis.yml ├── LICENSE ├── NOTICE ├── README.md ├── VERSION ├── bash-dtf ├── dtf.bash ├── dtf_core.sh └── dtf_log.sh ├── build.gradle ├── deb-scripts ├── postinstall └── postuninstall ├── dtf-binding └── dtfbinder ├── dtf-client-app ├── .gitignore ├── LICENSE ├── app │ ├── build.gradle │ ├── keys │ │ └── .gitignore │ ├── proguard-rules.txt │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ ├── assets │ │ ├── busybox-arm │ │ └── busybox-i686 │ │ ├── java │ │ └── com │ │ │ └── dtf │ │ │ └── client │ │ │ ├── BootReceiver.java │ │ │ ├── HelperService.java │ │ │ ├── InitializeService.java │ │ │ ├── NotificationService.java │ │ │ ├── ShellExecutor.java │ │ │ ├── SocketService.java │ │ │ └── Utils.java │ │ └── res │ │ ├── drawable-hdpi │ │ ├── ic_build_white_48dp.png │ │ └── ic_launcher.png │ │ ├── drawable-mdpi │ │ ├── ic_build_white_48dp.png │ │ └── ic_launcher.png │ │ ├── drawable-xhdpi │ │ ├── ic_build_white_48dp.png │ │ └── ic_launcher.png │ │ ├── drawable-xxhdpi │ │ ├── ic_build_white_48dp.png │ │ └── ic_launcher.png │ │ ├── values-v11 │ │ └── styles.xml │ │ ├── values-v14 │ │ └── styles.xml │ │ └── values │ │ ├── strings.xml │ │ └── styles.xml ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle ├── dtf-included ├── .gitignore ├── Makefile └── build │ └── included.tar ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── installscript └── install.sh ├── man ├── dtf-archive.ronn ├── dtf-binary.ronn ├── dtf-binding.ronn ├── dtf-check.ronn ├── dtf-client.ronn ├── dtf-init.ronn ├── dtf-library.ronn ├── dtf-local.ronn ├── dtf-module.ronn ├── dtf-package.ronn ├── dtf-pm.ronn ├── dtf-project.ronn ├── dtf-prop.ronn ├── dtf-reset.ronn ├── dtf-status.ronn ├── dtf-upgrade.ronn └── dtf.ronn ├── python-dtf ├── .coveragerc ├── .gitignore ├── MANIFEST.in ├── README.rst ├── dtf │ ├── __init__.py │ ├── adb.py │ ├── checker.py │ ├── client.py │ ├── colors.py │ ├── constants.py │ ├── core │ │ ├── __init__.py │ │ ├── autoconfig.py │ │ ├── cmds │ │ │ ├── __init__.py │ │ │ ├── archive.py │ │ │ ├── binding.py │ │ │ ├── client.py │ │ │ ├── init.py │ │ │ ├── local.py │ │ │ ├── pm.py │ │ │ ├── prop.py │ │ │ ├── reset.py │ │ │ ├── status.py │ │ │ └── upgrade.py │ │ ├── compat.py │ │ ├── item.py │ │ ├── manifestparser.py │ │ ├── packagemanager.py │ │ └── utils.py │ ├── exceptions.py │ ├── globals.py │ ├── included.py │ ├── launcher.py │ ├── library.py │ ├── logging.py │ ├── module.py │ ├── packages.py │ ├── properties.py │ └── testutils.py ├── generate_coverage.sh ├── pylint.config ├── setup.cfg ├── setup.py └── tests │ ├── data-files │ ├── hello-world.apk │ ├── integration_client_upload_data │ ├── integration_module_invalid_noclass │ ├── integration_module_invalid_noexecargs │ ├── integration_module_valid_kraise │ ├── integration_module_valid_mod │ ├── integration_module_valid_raise │ ├── integration_module_valid_subs │ ├── integration_pm_binary_install │ ├── integration_pm_install_library.dz │ ├── integration_pm_install_package.dz │ ├── integration_pm_module_install_bash │ ├── integration_pm_valid_zip.zip │ ├── nexus_5x │ └── valid_android_manifest.xml │ ├── integration-device │ └── client │ │ ├── test_client.py │ │ ├── test_client_download.py │ │ ├── test_client_execute.py │ │ ├── test_client_install.py │ │ ├── test_client_remove.py │ │ ├── test_client_restart.py │ │ ├── test_client_status.py │ │ └── test_client_upload.py │ ├── integration │ ├── archive │ │ └── test_archive.py │ ├── binding │ │ └── test_binding.py │ ├── local │ │ └── test_local.py │ ├── module │ │ └── test_module.py │ ├── pm │ │ ├── test_pm.py │ │ ├── test_pm_delete.py │ │ ├── test_pm_export.py │ │ ├── test_pm_install.py │ │ ├── test_pm_list.py │ │ ├── test_pm_purge.py │ │ └── test_pm_repo.py │ ├── prop │ │ ├── test_prop.py │ │ ├── test_prop_del.py │ │ ├── test_prop_dump.py │ │ ├── test_prop_get.py │ │ ├── test_prop_set.py │ │ └── test_prop_test.py │ ├── reset │ │ └── test_reset.py │ └── test_dtf.py │ └── unit │ ├── test_colors.py │ ├── test_included.py │ ├── test_log.py │ └── test_prop.py ├── release └── android-dtf_all.deb ├── requirements.txt ├── uninstall_1_3.sh └── wait_for_emulator /.gitignore: -------------------------------------------------------------------------------- 1 | # Some dtf stuff shouldn't be added. 2 | .dtf* 3 | .gradle 4 | build/ 5 | man/*.[0-9] 6 | 7 | # OS generated files # 8 | ###################### 9 | .DS_Store 10 | .DS_Store? 11 | ._* 12 | .Spotlight-V100 13 | .Trashes 14 | ehthumbs.db 15 | Thumbs.db 16 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | python: 3 | - "2.7" 4 | - "3.3" 5 | 6 | before_install: 7 | # apt-get packages first. 8 | - sudo apt-get -qq update 9 | - sudo apt-get install -y lintian devscripts shellcheck 10 | - if [ `uname -m` = x86_64 ]; then sudo apt-get install -qq libc6:i386 libgcc1:i386 gcc-4.6-base:i386 libstdc++5:i386 libstdc++6:i386 lib32z1 libreadline6-dev:i386 libncurses5-dev:i386; fi 11 | 12 | - if test ! -e $HOME/android-sdk-dl/sdk-tools.zip ; then curl https://dl.google.com/android/repository/sdk-tools-linux-3859397.zip > $HOME/android-sdk-dl/sdk-tools.zip ; fi 13 | - unzip -qq -n $HOME/android-sdk-dl/sdk-tools.zip -d $HOME/android-sdk 14 | 15 | # Install or update Android SDK components (will not do anything if already up to date thanks to the cache mechanism) 16 | - echo y | $HOME/android-sdk/tools/bin/sdkmanager 'tools' > /dev/null 17 | - echo y | $HOME/android-sdk/tools/bin/sdkmanager 'platform-tools' > /dev/null 18 | - echo y | $HOME/android-sdk/tools/bin/sdkmanager 'build-tools;26.0.2' > /dev/null 19 | - echo y | $HOME/android-sdk/tools/bin/sdkmanager 'platforms;android-22' > /dev/null 20 | - echo y | $HOME/android-sdk/tools/bin/sdkmanager 'system-images;android-22;default;armeabi-v7a' > /dev/null 21 | - export PATH=${PATH}:${ANDROID_HOME}/tools:${ANDROID_HOME}/platform-tools 22 | - export JAVA_HOME=/usr/lib/jvm/java-8-oracle 23 | 24 | # Create and start a AVD 25 | - echo no | $HOME/android-sdk/tools/bin/avdmanager create avd --force -n test -k "system-images;android-22;default;armeabi-v7a" 26 | - $HOME/android-sdk/emulator/emulator -avd test -no-audio -no-window & 27 | 28 | install: 29 | - pip install -r "requirements.txt" 30 | - pip install setuptools==28.7.1 31 | 32 | before_script: 33 | # Wait for emulator 34 | - ./wait_for_emulator 35 | 36 | script: ./gradlew --no-daemon buildDebugApk doCoverage 37 | 38 | branches: 39 | only: 40 | - dev 41 | 42 | git: 43 | depth: 5 44 | 45 | before_cache: 46 | - rm -f $HOME/.gradle/caches/modules-2/modules-2.lock 47 | - rm -rf $HOME/.gradle/caches/*/plugin-resolution/ 48 | 49 | cache: 50 | directories: 51 | # Android SDK 52 | - $HOME/android-sdk-dl 53 | - $HOME/android-sdk 54 | 55 | # Gradle dependencies 56 | - $HOME/.gradle/caches/ 57 | - $HOME/.gradle/wrapper/ 58 | 59 | # Android build cache (see http://tools.android.com/tech-docs/build-cache) 60 | - $HOME/.android/build-cache 61 | 62 | # pip caching. 63 | - $HOME/.cache/pip 64 | 65 | env: 66 | - ANDROID_HOME=$HOME/android-sdk 67 | 68 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Android Device Testing Framework (dtf) 2 | ====================================== 3 | 4 | [![Build Status](https://travis-ci.org/jakev/dtf.svg?branch=dev)](https://travis-ci.org/jakev/dtf) 5 | 6 | About 7 | ----- 8 | The Android Device Testing Framework (`dtf`) is a data collection and analysis framework to help individuals search for vulnerabilities on mobile devices. `dtf` _is not_ a: 9 | 10 | * Vulnerability scanner or explitation framework for mobile devices 11 | * An application assessment tool 12 | * A "turn your phone into a hacking device" tool 13 | 14 | Instead, `dtf` aims to allow testers to obtain information from their Android device, process this information into databases, and then start searching for vulnerabilities (all without requiring root privileges). These modules help you focus on changes made to AOSP components such as applications, frameworks, system services, as well as lower-level components such as binaries, libraries, and device drivers. In addition, you'll be able to analyze new functionality implemented by the OEMs and other parties to find vulnerabilities. 15 | 16 | ### Key Features 17 | * 30+ modules for collecting, processing, and interacting with a device 18 | * Builtin API for interfacing with your target device 19 | * Python and shell bindings for creating modules 20 | * Per-project property sub-system and logging/auditing 21 | * Bundled versions of numerous Android tools (think apktool/smali/dex2jar) 22 | 23 | Installing 24 | ---------- 25 | `dtf` is offically supported on Ubuntu, particularly versions 14 through 16. At this time there is no support for Windows or OS X. 26 | 27 | ### Manual Prerequisites 28 | The only manual installation requirement for `dtf` is the Android SDK (`dtf` relies on the `adb` utility). It is recommended that you install [Android Studio](https://developer.android.com/studio/install.html), and add `adb` to your `$PATH`. 29 | 30 | ### Installation Script 31 | To install `dtf` on Ubuntu (or update the framework), run the following commands: 32 | 33 | $ curl -sSL thecobraden.com/getdtf > install.sh 34 | $ chmod u+x install.sh 35 | $ ./install.sh 36 | 37 | If you're one of those people who doesn't trust the whole `curl|bash` model, just download the script from the [GitHub](https://github.com/android-dtf/dtf/blob/dev/installscript/install.sh) page. 38 | 39 | ### Managing Installed Content 40 | During installation, `dtf` will automatically configure itself to pull from the stable feed of core content. It is a good idea to routinely run the following command to ensure `dtf` remains up-to-date: 41 | 42 | $ dtf pm upgrade 43 | 44 | ### Upgrading from 1.3.0 45 | If you previously installed `dtf` version 1.3.0, you can use the uninstall script to ensure there are no conflicts: 46 | 47 | $ sudo ./uninstall_1_3.sh 48 | 49 | Note that `dtf` version 1.3.1 *does not* require any changes to a user's `$PATH`, so you should remove any `$PATH` changes related to `dtf`. 50 | 51 | Using dtf 52 | --------- 53 | Before using `dtf`, you'll need to enable USB debugging on your target device. If you're unsure of what this is, `dtf` is probably not the tool for you. Once it's enabled, update all Play applications, and connect the device to your PC. Assuming `adb` sees your device, we can create our project with the `init` built-in command: 54 | 55 | $ mkdir MyProject 56 | $ cd MyProject 57 | $ dtf init 58 | 59 | From here, you'll want to read up on each of the many modules that `dtf` supports. See the project Wiki for additional details on using `dtf`. 60 | 61 | Licenses 62 | -------- 63 | `dtf` is licensed under the Apache License, Version 2.0, but contains additional code from other projects. Check the NOTICE file for additional projects and licensing. 64 | 65 | Contributing & Building 66 | ----------------------- 67 | If you're interested in building your own instance of `dtf`, you'll need a couple of dependences: 68 | 69 | $ sudo apt-get install lintian python2.7 openjdk-8-jdk python-pip devscripts shellcheck 70 | $ sudo pip install flake8 pylint pytest pytest-runner wheel 71 | 72 | You can now build the project, which is currently limited to Debian '.deb' packages. To build `dtf`, run the following command from the project root: 73 | 74 | $ ./gradlew clean useDebugApk makeDeb 75 | 76 | ### Creating Content 77 | The `dtf` `man` pages are a great place to start. The `man` pages for `dtf-module(7)`, `dtf-binary(7)`, `dtf-library(7)` and `dtf-package(7)` will provide additional insight on the structure of `dtf` content. If you're creating a module, it's a good idea to ensure that it passes all the checks with the `dtf_check` utility. More information can be found in the `man` pages for `dtf-check(1)`. To check your new module: 78 | 79 | $ dtf_check -sa my_cool_module 80 | 81 | Questions & Comments 82 | -------------------- 83 | Please use the project's GitHub issue tracker for reporting bugs. For bugs related to a specific module, please use the issue tracker for that particular git repo. 84 | -------------------------------------------------------------------------------- /VERSION: -------------------------------------------------------------------------------- 1 | 1.3.2 2 | -------------------------------------------------------------------------------- /bash-dtf/dtf.bash: -------------------------------------------------------------------------------- 1 | # Android Device Testing Framework ("dtf") 2 | # Copyright 2013-2015 Jake Valletta (@jake_valletta) 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | # Bash Completion Script 17 | 18 | getroot () { 19 | 20 | if [ -f .dtfini ]; then echo "$PWD" && return; fi 21 | 22 | test / == "$PWD" && return || test -e "$1" && echo "$PWD" && return || cd .. && upsearch ".dtfini" 23 | } 24 | 25 | upsearch () { 26 | test / == "$PWD" && return || test -e "$1" && echo "$PWD" && return || cd .. && upsearch "$1" 27 | } 28 | 29 | _dtf() 30 | { 31 | MAIN_DB=~/.dtf/main.db 32 | 33 | local cur prev opts 34 | COMPREPLY=() 35 | cur="${COMP_WORDS[COMP_CWORD]}" 36 | prev="${COMP_WORDS[COMP_CWORD-1]}" 37 | opts="" 38 | 39 | TOP=$(getroot) 40 | 41 | CORE="archive binding client help init local modules pm prop reset status version" 42 | MODULES=$(dtf pm list modules -q 2>/dev/null|tr '\n' ' ') 43 | LOCAL_MODULES=$(ls "${TOP}/local_modules" 2>/dev/null) 44 | 45 | opts="${CORE} ${MODULES} ${LOCAL_MODULES}" 46 | 47 | if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then 48 | COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) 49 | return 0 50 | else 51 | COMPREPLY=( $(compgen -W "`ls`" -- ${cur}) ) 52 | return 0 53 | fi 54 | 55 | 56 | } 57 | complete -F _dtf dtf 58 | -------------------------------------------------------------------------------- /bash-dtf/dtf_core.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Android Device Testing Framework ("dtf") 3 | # Copyright 2013-2015 Jake Valletta (@jake_valletta) 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | # Modules that want to take advantage of built-in functionality should source this file. 18 | 19 | # This allows modules to access dtf resources 20 | DTF_DIR=~/.dtf 21 | DTF_BINS=${DTF_DIR}/binaries 22 | DTF_LIBS=${DTF_DIR}/libraries 23 | DTF_MODULES=${DTF_DIR}/modules 24 | DTF_PACKAGES=${DTF_DIR}/packages 25 | DTF_INCLUDED=${DTF_DIR}/included 26 | 27 | export DTF_BINS DTF_LIBS DTF_MODULES DTF_PACKAGES DTF_INCLUDED 28 | 29 | # API Levels for quick references. 30 | export API_1=1 31 | export API_2=2 32 | export API_CUPCAKE=3 33 | export API_DONUT=4 34 | export API_ECLAIR=5 35 | export API_ECLAIR_R1=6 36 | export API_ECLAIR_R2=7 37 | export API_FROYO=8 38 | export API_GINGERBREAD=9 39 | export API_GINGERBREAD_R1=10 40 | export API_HONEYCOMB=11 41 | export API_HONEYCOMB_R1=12 42 | export API_HONEYCOMB_R2=13 43 | export API_ICE_CREAM_SANDWICH=14 44 | export API_ICE_CREAM_SANDWICH_R1=15 45 | export API_JELLY_BEAN=16 46 | export API_JELLY_BEAN_R1=17 47 | export API_JELLY_BEAN_R2=18 48 | export API_KITKAT=19 49 | export API_WEAR=20 50 | export API_LOLLIPOP=21 51 | export API_LOLLIPOP_R1=22 52 | export API_MARSHMALLOW=23 53 | export API_NOUGAT=24 54 | 55 | # In the case of $TOP not being set, you can use this to obtain the project 56 | # path. Chances are that you won't ever need to call this. 57 | getroot () { 58 | 59 | if [ -f .dtfini ]; then echo "$PWD" && return; fi 60 | 61 | test / = "$PWD" && return || test -e "$1" && echo "$PWD" && return || cd .. && upsearch ".dtfini" 62 | } 63 | 64 | # Helper for obtaining project root. Not meant to be called (unless you wanted 65 | # to?) 66 | upsearch () { 67 | test / = "$PWD" && return || test -e "$1" && echo "$PWD" && return || cd .. && upsearch "$1" 68 | } 69 | 70 | # Top of the project. 71 | export TOP 72 | TOP=$(upsearch .dtfini) 73 | 74 | # Change back to the launch directory 75 | dtf_reset_dir() { 76 | 77 | cd "$LAUNCH_DIR" || exit 1 78 | } 79 | 80 | # Method to check if device is connected. 81 | # returns 1 if connected, 0 if not connected. 82 | dtf_device_connected () 83 | { 84 | state=$(adb get-state) 85 | 86 | if [ "$state" = "device" ]; then 87 | return 0 88 | fi 89 | 90 | return 1 91 | } 92 | 93 | # Check if a module is installed. 94 | dtf_has_module () 95 | { 96 | module_name=$1 97 | 98 | if dtf pm list modules -q |grep "\b${module_name}$" > /dev/null; then 99 | return 0 100 | else 101 | return 1 102 | fi 103 | } 104 | 105 | # Check if a binary is installed. 106 | dtf_has_binary () 107 | { 108 | binary_name=$1 109 | 110 | if dtf pm list binaries -q |grep "\b${binary_name}$" > /dev/null; then 111 | return 0 112 | else 113 | return 1 114 | fi 115 | } 116 | 117 | # Check if a library is installed. 118 | dtf_has_library () 119 | { 120 | library_name=$1 121 | 122 | if dtf pm list libraries -q |grep "\b${library_name}$" > /dev/null; then 123 | return 0 124 | else 125 | return 1 126 | fi 127 | } 128 | 129 | # Check if a package is installed. 130 | dtf_has_package () 131 | { 132 | package_name=$1 133 | 134 | if dtf pm list packages -q |grep "\b${package_name}$" > /dev/null; then 135 | return 0 136 | else 137 | return 1 138 | fi 139 | } 140 | -------------------------------------------------------------------------------- /bash-dtf/dtf_log.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Android Device Testing Framework ("dtf") 3 | # Copyright 2013-2015 Jake Valletta (@jake_valletta) 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | # Modules may source this file to use dtf's logging capabilities. 18 | 19 | # Taken from: https://gist.github.com/bcap/5682077#file-terminal-control-sh 20 | # Terminal output control (http://www.termsys.demon.co.uk/vtansi.htm) 21 | 22 | 23 | # Feel free to override these in your module. 24 | LOG_FILE=.dtflog 25 | LOG_LEVEL=4 26 | LOG_TO_STDOUT=1 27 | LOG_TO_FILE=1 28 | 29 | # Don't override the global logging. 30 | if [ -z "$GLOG_LEVEL" ]; then 31 | GLOG_LEVEL=$LOG_LEVEL 32 | fi 33 | 34 | ######################### 35 | # Format Notes: 36 | #[2013-01-02T12:00:31] testmodule/E - This is an error! 37 | # [], E, W, I, V, D 38 | # 0, 1, 2, 3, 4, 5 39 | ######################### 40 | 41 | COLOR_ERROR=$(tput setaf 1) 42 | COLOR_WARN=$(tput setaf 3) 43 | COLOR_INFO=$(tput setaf 2) 44 | COLOR_VERB=$(tput setaf 6) 45 | COLOR_DEB=$(tput setaf 5) 46 | COLOR_RST=$(tput sgr0) 47 | 48 | 49 | # Internal low-level logger 50 | _log() 51 | { 52 | date="[$(date)]" 53 | color=$1 54 | app=$2 55 | shift 56 | shift 57 | message=$* 58 | 59 | if [ "${LOG_TO_FILE}" -eq "1" ]; then 60 | echo "${date} ${app} - ${message}" >> ${LOG_FILE}; 61 | fi 62 | 63 | if [ "${LOG_TO_STDOUT}" -eq "1" ]; then 64 | printf "%s %s - %s\n" "${color}${date}" "${app}" "${message}${COLOR_RST}" 65 | fi 66 | } 67 | 68 | # Print an error message 69 | log_e() 70 | { 71 | LOG_LEVEL=$GLOG_LEVEL 72 | if [ "${LOG_LEVEL}" -ge 1 ]; then 73 | caller=$(basename "${0}") 74 | _log "${COLOR_ERROR}" "${caller}/E" "$@" 75 | fi 76 | } 77 | 78 | # Print a warning message 79 | log_w() 80 | { 81 | LOG_LEVEL=$GLOG_LEVEL 82 | if [ "${LOG_LEVEL}" -ge 2 ]; then 83 | caller=$(basename "${0}") 84 | _log "${COLOR_WARN}" "${caller}/W" "$@" 85 | fi 86 | } 87 | 88 | # Print an informational message 89 | log_i() 90 | { 91 | LOG_LEVEL=$GLOG_LEVEL 92 | if [ "${LOG_LEVEL}" -ge 3 ]; then 93 | caller=$(basename "${0}") 94 | _log "${COLOR_INFO}" "${caller}/I" "$@" 95 | fi 96 | } 97 | 98 | # Print a verbose message 99 | log_v() 100 | { 101 | LOG_LEVEL=$GLOG_LEVEL 102 | if [ "${LOG_LEVEL}" -ge 4 ]; then 103 | caller=$(basename "${0}") 104 | _log "${COLOR_VERB}" "${caller}/V" "$@" 105 | fi 106 | } 107 | 108 | # Print a debugging message 109 | log_d() 110 | { 111 | LOG_LEVEL=$GLOG_LEVEL 112 | if [ "${LOG_LEVEL}" -ge 5 ]; then 113 | caller=$(basename "${0}") 114 | _log "${COLOR_DEB}" "${caller}/D" "$@" 115 | fi 116 | } 117 | -------------------------------------------------------------------------------- /deb-scripts/postinstall: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | case "$1" in 4 | configure) 5 | pip install /tmp/dtf-*.whl 6 | ;; 7 | esac 8 | -------------------------------------------------------------------------------- /deb-scripts/postuninstall: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | case "$1" in 4 | remove) 5 | pip uninstall -y dtf 6 | ;; 7 | purge) 8 | rm -rf ~/.dtf 9 | ;; 10 | esac 11 | -------------------------------------------------------------------------------- /dtf-binding/dtfbinder: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Android Device Testing Framework ("dtf") 3 | # Copyright 2013-2016 Jake Valletta (@jake_valletta) 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | # Central point for dtf bindings 18 | 19 | # Helpers 20 | 21 | 22 | 23 | # This determines the real serial based on the current mode 24 | get_connection_serial () 25 | { 26 | mode=$(dtf prop get Client mode) 27 | 28 | if [ "$mode" = "usb" ]; then 29 | serial=$(dtf prop get Info serial) 30 | echo "$serial" 31 | elif [ "$mode" = "wifi" ]; then 32 | ip_addr=$(dtf prop get Client ip-addr) 33 | port=$(dtf prop get Client port) 34 | echo "${ip_addr}:${port}" 35 | fi 36 | } 37 | 38 | launch_shell() 39 | { 40 | ANDROID_SERIAL=$(get_connection_serial) adb shell "$@" 41 | 42 | return 0 43 | } 44 | 45 | launch_busybox() 46 | { 47 | busybox=$(dtf prop get Info busybox) 48 | serial=$(get_connection_serial) 49 | 50 | adb -s "${serial}" shell run-as com.dtf.client "${busybox}" "$@" 51 | } 52 | 53 | launch_aapt() 54 | { 55 | aapt_file=$(dtf binding dtf_aapt) 56 | if [ ! -r "$aapt_file" ]; then 57 | echo "dtf_aapt: can't find $aapt_file" 58 | return 1 59 | fi 60 | 61 | $aapt_file "$@" 62 | return $? 63 | } 64 | 65 | 66 | launch_abe() 67 | { 68 | jarfile=$(dtf binding dtf_abe) 69 | if [ ! -r "$jarfile" ]; then 70 | echo "dtf_abe: can't find $jarfile" 71 | return 1 72 | fi 73 | 74 | javaOpts="-Xmx256M" 75 | 76 | while expr "x$1" : 'x-J' >/dev/null; do 77 | opt=$(expr "$1" : '-J\(.*\)') 78 | javaOpts="${javaOpts} -${opt}" 79 | shift 80 | done 81 | 82 | jarpath="$jarfile" 83 | 84 | java "$javaOpts" -jar "$jarpath" "$@" 85 | 86 | return $? 87 | } 88 | 89 | launch_apktool() 90 | { 91 | jarfile=$(dtf binding dtf_apktool) 92 | if [ ! -r "$jarfile" ]; then 93 | echo "dtf_apktool: can't find $jarfile" 94 | return 1 95 | fi 96 | 97 | javaOpts="-Xmx256M" 98 | 99 | while expr "x$1" : 'x-J' >/dev/null; do 100 | opt=$(expr "$1" : '-J\(.*\)') 101 | javaOpts="${javaOpts} -${opt}" 102 | shift 103 | done 104 | 105 | jarpath="$jarfile" 106 | 107 | java "$javaOpts" -jar "$jarpath" "$@" 108 | 109 | return $? 110 | } 111 | 112 | launch_axmlprinter2() 113 | { 114 | jarfile=$(dtf binding dtf_axmlprinter2) 115 | if [ ! -r "$jarfile" ]; then 116 | echo "dtf_axmlprinter2: can't find $jarfile" 117 | return 1 118 | fi 119 | 120 | javaOpts="-Xmx256M" 121 | 122 | while expr "x$1" : 'x-J' >/dev/null; do 123 | opt=$(expr "$1" : '-J\(.*\)') 124 | javaOpts="${javaOpts} -${opt}" 125 | shift 126 | done 127 | 128 | jarpath="$jarfile" 129 | 130 | java "$javaOpts" -jar "$jarpath" "$@" 131 | 132 | return $? 133 | } 134 | 135 | launch_baksmali() 136 | { 137 | jarfile=$(dtf binding dtf_baksmali) 138 | if [ ! -r "$jarfile" ]; then 139 | echo "dtf_baksmali: can't find $jarfile" 140 | return 1 141 | fi 142 | 143 | javaOpts="-Xmx256M" 144 | 145 | while expr "x$1" : 'x-J' >/dev/null; do 146 | opt=$(expr "$1" : '-J\(.*\)') 147 | javaOpts="${javaOpts} -${opt}" 148 | shift 149 | done 150 | 151 | jarpath="$jarfile" 152 | 153 | java "$javaOpts" -jar "$jarpath" "$@" 154 | return $? 155 | } 156 | 157 | launch_smali() 158 | { 159 | jarfile=$(dtf binding dtf_smali) 160 | if [ ! -r "$jarfile" ]; then 161 | echo "dtf_smali: can't find $jarfile" 162 | return 1 163 | fi 164 | 165 | javaOpts="-Xmx256M" 166 | 167 | while expr "x$1" : 'x-J' >/dev/null; do 168 | opt=$(expr "$1" : '-J\(.*\)') 169 | javaOpts="${javaOpts} -${opt}" 170 | shift 171 | done 172 | 173 | jarpath="$jarfile" 174 | 175 | java "$javaOpts" -jar "$jarpath" "$@" 176 | 177 | return $? 178 | } 179 | 180 | # Main 181 | calling_bind=$(basename "$0") 182 | 183 | case $calling_bind in 184 | dtf_shell) 185 | launch_shell "$@" 186 | return 0 ;; 187 | dtf_busybox) 188 | launch_busybox "$@" 189 | return 0 ;; 190 | dtf_aapt) 191 | launch_aapt "$@" 192 | return $? ;; 193 | dtf_abe) 194 | launch_abe "$@" 195 | return $? ;; 196 | dtf_apktool) 197 | launch_apktool "$@" 198 | return $? ;; 199 | dtf_axmlprinter2) 200 | launch_axmlprinter2 "$@" 201 | return $? ;; 202 | dtf_baksmali) 203 | launch_baksmali "$@" 204 | return $? ;; 205 | dtf_smali) 206 | launch_smali "$@" 207 | return $? ;; 208 | # Don't call directly! 209 | dtfbinder) echo "Don't call binder directly!";; 210 | 211 | # Other... 212 | *) echo "Binding not found!" ;; 213 | esac 214 | -------------------------------------------------------------------------------- /dtf-client-app/.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | app/build/ 3 | app/src/main/bin/ 4 | app/src/main/gen/ 5 | build/ 6 | .idea/ 7 | .gradle 8 | /local.properties 9 | .DS_Store 10 | captures/ 11 | gen/ 12 | -------------------------------------------------------------------------------- /dtf-client-app/app/build.gradle: -------------------------------------------------------------------------------- 1 | import groovy.swing.SwingBuilder 2 | 3 | apply plugin: 'com.android.application' 4 | apply plugin: 'findbugs' 5 | 6 | System.setProperty('java.awt.headless', 'false') 7 | 8 | android { 9 | compileSdkVersion 25 10 | buildToolsVersion '26.0.2' 11 | 12 | defaultConfig { 13 | applicationId PACKAGE_NAME 14 | minSdkVersion 10 15 | targetSdkVersion 25 16 | versionCode VERSION_CODE.toInteger() 17 | versionName VERSION_NAME 18 | } 19 | 20 | signingConfigs { 21 | release { 22 | storeFile file("keys/ReleaseKeys.jks") 23 | keyAlias 'dtfReleaseKeys' 24 | storePassword "X" 25 | keyPassword "X" 26 | } 27 | } 28 | 29 | buildTypes { 30 | release { 31 | debuggable true 32 | minifyEnabled true 33 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt' 34 | signingConfig signingConfigs.release 35 | 36 | applicationVariants.all { variant -> 37 | variant.outputs.all { output -> 38 | 39 | outputFileName = "${PACKAGE_NAME}-${variant.versionName}-${variant.versionCode}.apk" 40 | } 41 | } 42 | 43 | } 44 | } 45 | 46 | lintOptions { 47 | abortOnError true 48 | } 49 | 50 | task findBugs(type: FindBugs, dependsOn: "assembleDebug") { 51 | 52 | description 'Run findbugs' 53 | group 'verification' 54 | 55 | classes = fileTree('build/intermediates/classes/debug/') 56 | source = fileTree('com/dtf/client') 57 | classpath = files() 58 | 59 | effort = 'max' 60 | reportLevel = 'high' 61 | 62 | reports { 63 | html.enabled = true 64 | xml.enabled = false 65 | } 66 | } 67 | } 68 | 69 | task askForPasswords << { 70 | 71 | def console = System.console() 72 | def storePw 73 | def keyPw 74 | 75 | if (console) { 76 | storePw = new String(console.readPassword("\nKeystore password: ")) 77 | keyPw = new String(console.readPassword("Key password: ")) 78 | } else { 79 | // Gradle is running as a daemon - prompt user to enter passwords via popup UI (#770) 80 | new SwingBuilder().edt { 81 | dialog(modal: true, title: 'Enter credentials', alwaysOnTop: true, resizable: true, 82 | locationRelativeTo: null, pack: true, show: true 83 | ) { 84 | vbox { 85 | label(text: "Keystore passphrase:") 86 | textField id: "storeText", input = passwordField() 87 | label(text: "Key passphrase:") 88 | textField id: "keyText", input = passwordField() 89 | button(defaultButton: true, text: 'OK', actionPerformed: { 90 | storePw = storeText.text; 91 | keyPw = keyText.text; 92 | dispose(); 93 | }) 94 | } 95 | } 96 | } 97 | } 98 | 99 | android.signingConfigs.release.storePassword = storePw 100 | android.signingConfigs.release.keyPassword = keyPw 101 | } 102 | 103 | // Tricks for password prompt 104 | tasks.whenTaskAdded { theTask -> 105 | if (theTask.name.matches("packageRelease")) { 106 | theTask.dependsOn "askForPasswords" 107 | } 108 | } 109 | 110 | dependencies { 111 | compile "com.android.support:support-core-utils:25.4.0" 112 | } 113 | 114 | afterEvaluate { 115 | assembleRelease.dependsOn findBugs 116 | } 117 | -------------------------------------------------------------------------------- /dtf-client-app/app/keys/.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore everything in this directory 2 | * 3 | # Except this file 4 | !.gitignore 5 | -------------------------------------------------------------------------------- /dtf-client-app/app/proguard-rules.txt: -------------------------------------------------------------------------------- 1 | # To enable ProGuard in your project, edit project.properties 2 | # to define the proguard.config property as described in that file. 3 | # 4 | # Add project specific ProGuard rules here. 5 | # By default, the flags in this file are appended to flags specified 6 | # in ${sdk.dir}/tools/proguard/proguard-android.txt 7 | # You can edit the include path and order by changing the ProGuard 8 | # include property in project.properties. 9 | # 10 | # For more details, see 11 | # http://developer.android.com/guide/developing/tools/proguard.html 12 | 13 | # Add any project specific keep options here: 14 | 15 | # If your project uses WebView with JS, uncomment the following 16 | # and specify the fully qualified class name to the JavaScript interface 17 | # class: 18 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 19 | # public *; 20 | #} 21 | -------------------------------------------------------------------------------- /dtf-client-app/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 15 | 16 | 21 | 22 | 23 | 24 | 25 | 26 | 31 | 32 | 33 | 34 | 35 | 36 | 40 | 41 | 42 | 43 | 44 | 45 | 49 | 50 | 51 | 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /dtf-client-app/app/src/main/assets/busybox-arm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/android-dtf/dtf/a761ace77cea051bfb88d56df65ae6b83f664480/dtf-client-app/app/src/main/assets/busybox-arm -------------------------------------------------------------------------------- /dtf-client-app/app/src/main/assets/busybox-i686: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/android-dtf/dtf/a761ace77cea051bfb88d56df65ae6b83f664480/dtf-client-app/app/src/main/assets/busybox-i686 -------------------------------------------------------------------------------- /dtf-client-app/app/src/main/java/com/dtf/client/BootReceiver.java: -------------------------------------------------------------------------------- 1 | package com.dtf.client; 2 | 3 | import android.content.BroadcastReceiver; 4 | import android.content.Context; 5 | import android.content.Intent; 6 | 7 | public class BootReceiver extends BroadcastReceiver { 8 | 9 | public BootReceiver() { 10 | } 11 | 12 | @Override 13 | public void onReceive(Context context, Intent intent) { 14 | 15 | if(intent.getAction().equals("android.intent.action.BOOT_COMPLETED")) { 16 | 17 | /* Start the notification banner */ 18 | context.startService(new Intent(context, NotificationService.class)); 19 | 20 | /* Start the LocalSocketServer */ 21 | context.startService(new Intent(context, SocketService.class)); 22 | } 23 | 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /dtf-client-app/app/src/main/java/com/dtf/client/HelperService.java: -------------------------------------------------------------------------------- 1 | package com.dtf.client; 2 | 3 | import android.app.IntentService; 4 | import android.content.Intent; 5 | import android.util.Log; 6 | 7 | 8 | public class HelperService extends IntentService { 9 | 10 | private static final String ACTION_RESTART_SOCKET = "com.dtf.action.name.RESTART_SOCKET"; 11 | 12 | private static final String TAG = "DtfHelperService"; 13 | 14 | public HelperService() { 15 | super("HelperService"); 16 | } 17 | 18 | @Override 19 | protected void onHandleIntent(Intent intent) { 20 | if (intent != null) { 21 | final String action = intent.getAction(); 22 | 23 | if (ACTION_RESTART_SOCKET.equals(action)) { 24 | handleActionRestartSocket(); 25 | } 26 | } 27 | } 28 | 29 | private void handleActionRestartSocket() { 30 | 31 | if (SocketService.isRunning) { 32 | 33 | // First stop the socket service. 34 | Log.d(TAG, "Stopping the socket service..."); 35 | 36 | this.stopService(new Intent(this, SocketService.class)); 37 | 38 | } else { 39 | Log.d(TAG, "Socket service is not running, skipping..."); 40 | } 41 | 42 | // Give it 2 seconds to cool down 43 | try { 44 | Thread.sleep(2000); 45 | } catch (InterruptedException e) { 46 | e.printStackTrace(); 47 | } 48 | 49 | // Now start it! 50 | Log.d(TAG, "Starting socket service!"); 51 | this.startService(new Intent(this, SocketService.class)); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /dtf-client-app/app/src/main/java/com/dtf/client/InitializeService.java: -------------------------------------------------------------------------------- 1 | /* Android Device Testing Framework ("dtf") 2 | * Copyright 2013-2014 Jake Valletta (@jake_valletta) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | package com.dtf.client; 18 | 19 | import android.app.IntentService; 20 | import android.content.Intent; 21 | import android.content.res.AssetManager; 22 | import android.util.Log; 23 | 24 | import java.io.File; 25 | import java.io.FileOutputStream; 26 | import java.io.IOException; 27 | import java.io.InputStream; 28 | import java.io.OutputStream; 29 | 30 | public class InitializeService extends IntentService { 31 | 32 | private final String TAG = "DtfInitializeService"; 33 | 34 | public InitializeService() { 35 | super("InitializeService"); 36 | } 37 | 38 | @Override 39 | protected void onHandleIntent(Intent intent) { 40 | 41 | Log.d(TAG, "Copying assets..."); 42 | int resp = copyAssets(); 43 | Log.d(TAG, "Copy completed: " + resp); 44 | 45 | Log.d(TAG, "Setting file directory as executable..."); 46 | resp = setExecutable(); 47 | Log.d(TAG, "Set complete: " + resp); 48 | 49 | /* Start the notification banner */ 50 | this.startService(new Intent(this, NotificationService.class)); 51 | 52 | /* Start the LocalSocketServer */ 53 | this.startService(new Intent(this, SocketService.class)); 54 | 55 | } 56 | 57 | private int copyAssets() { 58 | 59 | String busyboxFile = ""; 60 | if (Utils.isArm()) { 61 | busyboxFile = "busybox-arm"; 62 | } 63 | else if (Utils.isIntel()) { 64 | busyboxFile = "busybox-i686"; 65 | } 66 | 67 | else { 68 | Log.e(TAG, "Unable to determine CPU type!"); 69 | } 70 | 71 | AssetManager assetManager = getAssets(); 72 | String[] files = null; 73 | 74 | try { 75 | files = assetManager.list(""); 76 | } catch (IOException e) { 77 | Log.e("tag", "Failed to get asset file list.", e); 78 | return -1; 79 | } 80 | 81 | for(String filename : files) { 82 | if (filename.equals(busyboxFile)) { 83 | 84 | Log.d(TAG, "Copying asset: " + busyboxFile); 85 | 86 | InputStream in = null; 87 | OutputStream out = null; 88 | 89 | try { 90 | in = assetManager.open(busyboxFile); 91 | File outFile = new File(this.getFilesDir()+"/", "busybox"); 92 | 93 | out = new FileOutputStream(outFile); 94 | copyFile(in, out); 95 | in.close(); 96 | in = null; 97 | out.flush(); 98 | out.close(); 99 | out = null; 100 | 101 | // Make it world executable. 102 | outFile.setExecutable(true, false); 103 | 104 | } catch(IOException e) { 105 | Log.e("tag", "Failed to copy asset file: " + filename, e); 106 | return -2; 107 | } 108 | } 109 | } 110 | return 0; 111 | } 112 | 113 | private int setExecutable() { 114 | 115 | Process p = null; 116 | try { 117 | p = Runtime.getRuntime().exec("chmod 777 /data/data/com.dtf.client/files"); 118 | p.waitFor(); 119 | } catch (InterruptedException e) { 120 | Log.e(TAG, "Unable to open permissions on files directory!"); 121 | return -1; 122 | } catch (IOException e) { 123 | Log.e(TAG, "Unable to open permissions on files directory!"); 124 | return -2; 125 | } 126 | 127 | return 0; 128 | } 129 | 130 | private void copyFile(InputStream in, OutputStream out) throws IOException { 131 | byte[] buffer = new byte[1024]; 132 | int read; 133 | while((read = in.read(buffer)) != -1){ 134 | out.write(buffer, 0, read); 135 | } 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /dtf-client-app/app/src/main/java/com/dtf/client/NotificationService.java: -------------------------------------------------------------------------------- 1 | package com.dtf.client; 2 | 3 | import android.app.IntentService; 4 | import android.app.Notification; 5 | import android.app.NotificationManager; 6 | import android.app.PendingIntent; 7 | import android.content.Context; 8 | import android.content.Intent; 9 | import android.graphics.BitmapFactory; 10 | import android.net.Uri; 11 | import android.os.Build; 12 | import android.support.v4.app.NotificationCompat; 13 | import android.util.Log; 14 | 15 | 16 | public class NotificationService extends IntentService { 17 | 18 | NotificationManager notificationManager; 19 | private static final int NOTIFICATION_ID = 1; 20 | private static final String TAG = "NotificationService"; 21 | 22 | public NotificationService() { 23 | super("NotificationService"); 24 | } 25 | 26 | @Override 27 | protected void onHandleIntent(Intent intent) { 28 | stickyNotification(); 29 | } 30 | 31 | private void stickyNotification() { 32 | 33 | Log.d(TAG, "Creating our sticky notification!"); 34 | 35 | notificationManager = 36 | (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); 37 | 38 | Intent i = new Intent(); 39 | i.setAction(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS); 40 | i.setData(Uri.parse("package:com.dtf.client")); 41 | 42 | PendingIntent pendingIntent = PendingIntent.getActivity(this, 43 | NOTIFICATION_ID, i, PendingIntent.FLAG_UPDATE_CURRENT); 44 | 45 | Notification n; 46 | 47 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) { 48 | 49 | NotificationCompat.Builder builder = new NotificationCompat.Builder(this) 50 | .setContentTitle("dtfClient is Installed!") 51 | .setContentText("Click here to uninstall") 52 | .setContentIntent(pendingIntent) 53 | .setSmallIcon(R.drawable.ic_build_white_48dp) 54 | .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher)); 55 | 56 | n = builder.build(); 57 | } else { 58 | 59 | Notification.Builder builder = new Notification.Builder(this) 60 | .setContentTitle("dtfClient is Installed!") 61 | .setContentText("Click here to uninstall") 62 | .setContentIntent(pendingIntent) 63 | .setSmallIcon(R.drawable.ic_build_white_48dp) 64 | .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher)); 65 | n = builder.build(); 66 | } 67 | 68 | n.flags |= Notification.FLAG_NO_CLEAR | Notification.FLAG_ONGOING_EVENT; 69 | notificationManager.notify(NOTIFICATION_ID, n); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /dtf-client-app/app/src/main/java/com/dtf/client/ShellExecutor.java: -------------------------------------------------------------------------------- 1 | package com.dtf.client; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.InputStreamReader; 5 | import java.nio.charset.Charset; 6 | 7 | public class ShellExecutor { 8 | 9 | public ShellExecutor() { 10 | 11 | } 12 | 13 | public String execute(String command) { 14 | 15 | StringBuffer output = new StringBuffer(); 16 | 17 | Process p; 18 | try { 19 | p = Runtime.getRuntime().exec(command); 20 | p.waitFor(); 21 | BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream(), 22 | Charset.forName("UTF-8"))); 23 | 24 | String line; 25 | while ((line = reader.readLine())!= null) { 26 | output.append(line + "\n"); 27 | } 28 | 29 | } catch (Exception e) { 30 | e.printStackTrace(); 31 | } 32 | String response = output.toString(); 33 | return response; 34 | 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /dtf-client-app/app/src/main/java/com/dtf/client/Utils.java: -------------------------------------------------------------------------------- 1 | package com.dtf.client; 2 | 3 | 4 | import android.os.Build; 5 | 6 | public class Utils { 7 | 8 | static String cpu = Build.CPU_ABI; 9 | 10 | static boolean isIntel() { 11 | 12 | if (cpu.startsWith("x86")) { 13 | return true; 14 | } 15 | return false; 16 | } 17 | 18 | static boolean isArm() { 19 | 20 | if (cpu.startsWith("arm")) { 21 | return true; 22 | } 23 | return false; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /dtf-client-app/app/src/main/res/drawable-hdpi/ic_build_white_48dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/android-dtf/dtf/a761ace77cea051bfb88d56df65ae6b83f664480/dtf-client-app/app/src/main/res/drawable-hdpi/ic_build_white_48dp.png -------------------------------------------------------------------------------- /dtf-client-app/app/src/main/res/drawable-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/android-dtf/dtf/a761ace77cea051bfb88d56df65ae6b83f664480/dtf-client-app/app/src/main/res/drawable-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /dtf-client-app/app/src/main/res/drawable-mdpi/ic_build_white_48dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/android-dtf/dtf/a761ace77cea051bfb88d56df65ae6b83f664480/dtf-client-app/app/src/main/res/drawable-mdpi/ic_build_white_48dp.png -------------------------------------------------------------------------------- /dtf-client-app/app/src/main/res/drawable-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/android-dtf/dtf/a761ace77cea051bfb88d56df65ae6b83f664480/dtf-client-app/app/src/main/res/drawable-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /dtf-client-app/app/src/main/res/drawable-xhdpi/ic_build_white_48dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/android-dtf/dtf/a761ace77cea051bfb88d56df65ae6b83f664480/dtf-client-app/app/src/main/res/drawable-xhdpi/ic_build_white_48dp.png -------------------------------------------------------------------------------- /dtf-client-app/app/src/main/res/drawable-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/android-dtf/dtf/a761ace77cea051bfb88d56df65ae6b83f664480/dtf-client-app/app/src/main/res/drawable-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /dtf-client-app/app/src/main/res/drawable-xxhdpi/ic_build_white_48dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/android-dtf/dtf/a761ace77cea051bfb88d56df65ae6b83f664480/dtf-client-app/app/src/main/res/drawable-xxhdpi/ic_build_white_48dp.png -------------------------------------------------------------------------------- /dtf-client-app/app/src/main/res/drawable-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/android-dtf/dtf/a761ace77cea051bfb88d56df65ae6b83f664480/dtf-client-app/app/src/main/res/drawable-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /dtf-client-app/app/src/main/res/values-v11/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /dtf-client-app/app/src/main/res/values-v14/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /dtf-client-app/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | dtf Client 4 | 5 | 6 | -------------------------------------------------------------------------------- /dtf-client-app/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 14 | 15 | 16 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /dtf-client-app/build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | buildscript { 3 | repositories { 4 | jcenter() 5 | google() 6 | } 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:3.0.1' 9 | } 10 | } 11 | 12 | allprojects { 13 | repositories { 14 | jcenter() 15 | google() 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /dtf-client-app/gradle.properties: -------------------------------------------------------------------------------- 1 | PACKAGE_NAME=com.dtf.client 2 | VERSION_NAME=1.0 3 | VERSION_CODE=4 4 | -------------------------------------------------------------------------------- /dtf-client-app/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/android-dtf/dtf/a761ace77cea051bfb88d56df65ae6b83f664480/dtf-client-app/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /dtf-client-app/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Sat Nov 11 12:41:45 PST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip 7 | -------------------------------------------------------------------------------- /dtf-client-app/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn ( ) { 37 | echo "$*" 38 | } 39 | 40 | die ( ) { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 158 | function splitJvmOpts() { 159 | JVM_OPTS=("$@") 160 | } 161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 163 | 164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 165 | -------------------------------------------------------------------------------- /dtf-client-app/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /dtf-client-app/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | -------------------------------------------------------------------------------- /dtf-included/.gitignore: -------------------------------------------------------------------------------- 1 | src/ 2 | out/ 3 | -------------------------------------------------------------------------------- /dtf-included/Makefile: -------------------------------------------------------------------------------- 1 | setup: 2 | mkdir -p src/ 3 | mkdir -p out/ 4 | 5 | abe: setup 6 | git clone https://github.com/nelenkov/android-backup-extractor.git src/abe 7 | cd src/abe; \ 8 | wget https://www.bouncycastle.org/download/bcprov-jdk15on-158.jar -O lib/bcprov-jdk15on-158.jar; \ 9 | ./gradlew build shadowJar; \ 10 | cp ./build/libs/abe-all.jar ../../out/abe.jar 11 | 12 | apktool: setup 13 | git clone git://github.com/iBotPeaches/Apktool.git src/apktool 14 | cd src/apktool; \ 15 | ./gradlew build shadowJar; \ 16 | cp ./brut.apktool/apktool-cli/build/libs/apktool-cli-all.jar ../../out/apktool.jar; \ 17 | cp ./brut.apktool/apktool-lib/src/main/resources/prebuilt/linux/aapt ../../out/aapt 18 | 19 | axmlprinter: setup 20 | git clone https://github.com/rednaga/axmlprinter src/axmlprinter2 21 | cd src/axmlprinter2; \ 22 | ./gradlew jar; \ 23 | cp ./build/libs/axmlprinter*.jar ../../out/axmlprinter2.jar 24 | 25 | smali: setup 26 | git clone https://github.com/JesusFreke/smali.git src/smali 27 | cd src/smali; \ 28 | ./gradlew build; \ 29 | cp ./smali/build/libs/smali.jar ../../out/smali.jar; \ 30 | cp ./baksmali/build/libs/baksmali.jar ../../out/baksmali.jar 31 | 32 | version: 33 | echo $(shell date +%Y-%m-%d) > out/VERSION 34 | 35 | tar: version 36 | cd out; \ 37 | tar -cf ../build/included.tar ./* 38 | 39 | fatTar: abe apktool axmlprinter smali tar 40 | 41 | clean: 42 | rm -rf src/ 43 | rm -rf out/ 44 | rm -rf build/* 45 | -------------------------------------------------------------------------------- /dtf-included/build/included.tar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/android-dtf/dtf/a761ace77cea051bfb88d56df65ae6b83f664480/dtf-included/build/included.tar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/android-dtf/dtf/a761ace77cea051bfb88d56df65ae6b83f664480/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | zipStoreBase=GRADLE_USER_HOME 4 | zipStorePath=wrapper/dists 5 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-bin.zip 6 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /man/dtf-archive.ronn: -------------------------------------------------------------------------------- 1 | dtf-archive(1) -- Create a ZIP archive for your project 2 | ======================================================= 3 | 4 | ## SYNOPSIS 5 | dtf archive [subcommand] [] 6 | 7 | Subcommands: 8 | create Archive the current project. 9 | 10 | ## DESCRIPTION 11 | dtf-archive(1) is used to create a ZIP file containing all files for a given dtf(1) project for archiving purposes. By default, it uses the version string set by dtf-init(1). 12 | 13 | ## EXAMPLES 14 | Create an archive using the default version string: 15 | $ dtf archive create 16 | 17 | Create an archive called : 18 | $ dtf archive create my_archive.zip 19 | 20 | ## AUTHOR 21 | Jake Valletta 22 | 23 | ## DTF 24 | Part of the dtf(1) suite. 25 | -------------------------------------------------------------------------------- /man/dtf-binary.ronn: -------------------------------------------------------------------------------- 1 | dtf-binary(7) -- dtf binary documentation 2 | ========================================= 3 | 4 | ## DESCRIPTION 5 | A dtf-binary(7) is an executable file that is needed by a module. Currently, there is no support for architectures or versions of Linux. Use with caution. A dtf-binary(7) is installed using dtf-pm(1). 6 | 7 | ## EXAMPLES 8 | A dtf-binary(7) can be launched using a python-based dtf-module(7) using the **dtf.package** class: 9 | 10 | import dtf.package as pm 11 | 12 | ... 13 | 14 | # Launch executable 15 | pm.launch_binary('somebin') 16 | 17 | # Using the launcher= to specify how to load 18 | pm.launch_binary('some_java_bin', launcher='java -jar') 19 | 20 | ## AUTHOR 21 | Jake Valletta 22 | 23 | ## DTF 24 | Part of the dtf(1) suite. 25 | 26 | ## SEE ALSO 27 | dtf-pm(1), dtf-local(1), dtf-library(7), dtf-module(7), dtf-package(7) 28 | -------------------------------------------------------------------------------- /man/dtf-binding.ronn: -------------------------------------------------------------------------------- 1 | dtf-binding(1) -- View bindings for built-in tools 2 | ================================================== 3 | 4 | ## SYNOPSIS 5 | dtf binding [] 6 | 7 | ## DESCRIPTION 8 | dtf-binding(1) prints a single dtf binding or all bindings for built-in tools. This lets a modules use the **dtf.included** python class and **dtf_\*** helpers to invoke Android tools such as aapt and apktool. 9 | 10 | ## EXAMPLES 11 | To print all bindings, run dtf-binding(1) with no arguments: 12 | 13 | $ dtf binding 14 | 15 | To print a single binding, supply it as argument 1: 16 | 17 | $ dtf binding dtf_apktool 18 | 19 | The purpose of this system is to allow hotswapping of built-in tools. For example, suppose a specific version of smali is desired for a given project. You can edit the file "~/.dtf/included/globals.ini" to reflect this. Now, when using dtf(1), this new tool will be used. 20 | 21 | ## AUTHOR 22 | Jake Valletta 23 | 24 | ## DTF 25 | Part of the dtf(1) suite. 26 | -------------------------------------------------------------------------------- /man/dtf-check.ronn: -------------------------------------------------------------------------------- 1 | dtf-check(1) -- Check a dtf Module for errors and style 2 | ======================================================= 3 | 4 | ## SYNOPSIS 5 | dtf check -s -a [] 6 | 7 | ## DESCRIPTION 8 | dtf-check(1) checks a dtf-module(7) for syntax and style weaknesses. Those who wish to contribute to dtf(1) should use this utility to ensure they are introducing robust and readadble code. Since dtf-check(1) uses the same functions used by dtf(1) to load modules, it ensures the specified module: 9 | - Will be detected as a python or bash module 10 | - Will pass all autoparse checks 11 | - Contains only best practice values in autoparse 12 | - Will pass `pylint` and `flake8` checks (optional) 13 | 14 | ## EXAMPLES 15 | dtf-check(1) takes a **file_name** argument: 16 | 17 | $ dtf_check mynewmodule 18 | 19 | To run dtf-check(1) will all checks, use the all (**-a**) argument: 20 | 21 | $ dtf_check -a mynewmodule 22 | 23 | If you want to treat warnings as errors (recommended), use the strict (**-s**) argument: 24 | 25 | $ dtf_check -sa mynewmodule 26 | 27 | For more information on creating modules, see dtf-module(7). 28 | 29 | ## AUTHOR 30 | Jake Valletta 31 | 32 | ## DTF 33 | Part of the dtf(1) suite. 34 | -------------------------------------------------------------------------------- /man/dtf-client.ronn: -------------------------------------------------------------------------------- 1 | dtf-client(1) -- Interact with dtfClient on device 2 | ================================================== 3 | 4 | ## SYNOPSIS 5 | dtf client [subcommand] [] 6 | 7 | Subcommands: 8 | download Download a file using dtfClient. 9 | execute Execute a command using dtfClient. 10 | install Install the dtf client on device. 11 | status Print the install status of the client. 12 | remove Uninstall the dtf client. 13 | restart Restart dtfClient's socket service. 14 | upload Upload file using dtfClient. 15 | 16 | ## DESCRIPTION 17 | dtf-client(1) is used to interact with the dtfClient ("com.dtf.client") installed on your project device. 18 | 19 | ## EXAMPLES 20 | Determine if a device has the dtfClient application installed: 21 | $ dtf client status 22 | 23 | Install the dtfClient on a test device: 24 | $ dtf client install 25 | 26 | Restart any dtfClient services (useful for troubleshooting): 27 | $ dtf client restart 28 | 29 | Upload a file to the dtfClient's data directory: 30 | $ dtf client upload some_file.txt 31 | 32 | Download a file from the dtfClient's data directory and rename: 33 | $ dtf client download some.db --path ./users.db 34 | 35 | Execute a command using the dtfClient: 36 | $ dtf client execute ls /mnt/sdcard 37 | 38 | Remove the dtfClient application: 39 | $ dtf client remove 40 | 41 | ## AUTHOR 42 | Jake Valletta 43 | 44 | ## DTF 45 | Part of the dtf(1) suite. 46 | -------------------------------------------------------------------------------- /man/dtf-init.ronn: -------------------------------------------------------------------------------- 1 | dtf-init(1) -- Initialize a dtf project 2 | ======================================= 3 | 4 | ## SYNOPSIS 5 | dtf init 6 | 7 | ## DESCRIPTION 8 | dtf-init(1) creates an dtf(1) project in the current directory. It will install the dtfClient onto a test device, and create a boilerplate directory structure (see dtf-project(7) for more information on what emcompasses a dtf project). 9 | 10 | ## EXAMPLES 11 | In order to use dtf(1), you'll need to initialize a project. Before doing so, make sure that USB debugging is enabled on your test device, the device is connected, and your test machine's RSA keys are trusted. Once all of these are met, you can create your project with dtf-init(1): 12 | 13 | $ mkdir new_project 14 | $ cd new_project 15 | $ dtf init 16 | 17 | See dtf-reset(1) deleting a dtf project. 18 | 19 | ## AUTHOR 20 | Jake Valletta 21 | 22 | ## DTF 23 | Part of the dtf(1) suite. 24 | -------------------------------------------------------------------------------- /man/dtf-library.ronn: -------------------------------------------------------------------------------- 1 | dtf-library(7) -- dtf library documentation 2 | =========================================== 3 | 4 | ## DESCRIPTION 5 | A dtf-library(7) is a collection of python files used by a dtf-module(7). A dtf-library(7) is installed using dtf-pm(1). 6 | 7 | ## AUTHOR 8 | Jake Valletta 9 | 10 | ## DTF 11 | Part of the dtf(1) suite. 12 | 13 | ## SEE ALSO 14 | dtf-pm(1), dtf-local(1), dtf-binary(7), dtf-module(7), dtf-package(7) 15 | -------------------------------------------------------------------------------- /man/dtf-local.ronn: -------------------------------------------------------------------------------- 1 | dtf-local(1) -- Print all local (non-global) modules 2 | ==================================================== 3 | 4 | ## SYNOPSIS 5 | dtf local 6 | 7 | ## DESCRIPTION 8 | dtf-local(1) prints all local (non-global) modules. Note that a local module will take precedence over a global module. 9 | 10 | ## EXAMPLES 11 | dtf-local(1) does not take any arguments, and does not have any subcommands. To print local modules: 12 | 13 | $ cd my_project 14 | $ dtf local 15 | 16 | Local modules are parsed the same as global modules. The only difference is that local modules exist in the _local_modules/_ directory of a project (they do not need to be installed with dtf-pm(1)). See dtf-project(7) for more information about a dtf(1) project structure. 17 | 18 | ## AUTHOR 19 | Jake Valletta 20 | 21 | ## DTF 22 | Part of the dtf(1) suite. 23 | -------------------------------------------------------------------------------- /man/dtf-module.ronn: -------------------------------------------------------------------------------- 1 | dtf-module(7) -- dtf module documentation 2 | ========================================= 3 | 4 | ## DESCRIPTION 5 | A dtf-module(7) can be either a python class or shell script. A module performs a single task or mulitple tasks. A dtf-module(7) can import a dtf-library(7), and can execute a dtf-binary(7). 6 | 7 | ## PYTHON MODULES 8 | Python modules must extend the **dtf.Module** class, where the class name is the same as the file name. The entry point to a dtf-module(7) is the **execute(self, args)** method, and must be implemented. Python modules can take advantage of a dtf-library(7) using **import**. Python modules also use functionality exposed by **dtf.\***. The use of **dtf.core.\*** classes are strongly discouraged. 9 | 10 | ## BASH MODULES 11 | Bash modules do not contain nearly as much functionality as a python-based dtf-module(7). A bash dtf-module(7) is designed to perform simple tasks or for prototyping. Bash modules must have a supported shebang, starting in "#!" and ending with "sh", such as "#!/usr/bin/ksh". Bash modules can source API's from the **DTF_CORE** and **DTF_LOG** environment variables as follows: 12 | \. $DTF_CORE 13 | \. $DTF_LOG 14 | 15 | ## MODULE PROPERTIES 16 | Each module can be installed with dtf-pm(1), or tested/executed locally from a project's _local_modules_ directory with dtf-local(1). dtf-pm(1) supports installing packages with metadata. The following metadata fields are supported (Python|Bash): 17 | 18 | about|About = A one sentence description of the module. 19 | author|Author = The author of the module. 20 | name|N/A = The name of the module (should match name of class. 21 | version|Version - The version of the module, in semantic version format. 22 | 23 | Python modules can also take advantage of the following properties (no Bash support): 24 | 25 | min_sdk = The minimum required SDK. 26 | requires = A list of command-line utilities required. 27 | 28 | ## PYTHON EXAMPLE 29 | A trival python dtf-module(7) example called newmodule is: 30 | 31 | from dtf.module import Module 32 | 33 | class newmodule(Module): 34 | 35 | about = "A new, fun module" 36 | author = "Some Hacker (mygithub)" 37 | name = "newmodule" 38 | version = "1.3.0" 39 | 40 | def execute(self, args): 41 | 42 | print "Hello, world!" 43 | 44 | ## BASH EXAMPLE 45 | A trival bash dtf-module(7) example called newmodule is: 46 | 47 | #!/usr/bin/bash 48 | 49 | \. $DTF_CORE 50 | \. $DTF_LOG 51 | 52 | log_i "Hello world!"` 53 | 54 | ## AUTHOR 55 | Jake Valletta 56 | 57 | ## DTF 58 | Part of the dtf(1) suite. 59 | 60 | ## SEE ALSO 61 | dtf-pm(1), dtf-local(1), dtf-binary(7), dtf-library(7), dtf-package(7) 62 | -------------------------------------------------------------------------------- /man/dtf-package.ronn: -------------------------------------------------------------------------------- 1 | dtf-package(7) -- dtf package documentation 2 | =========================================== 3 | 4 | ## DESCRIPTION 5 | A dtf-package(7) is collection of files avaiable to modules. Use with caution. A dtf-package(7) is installed using dtf-pm(1). 6 | 7 | ## AUTHOR 8 | Jake Valletta 9 | 10 | ## DTF 11 | Part of the dtf(1) suite. 12 | 13 | ## SEE ALSO 14 | dtf-pm(1), dtf-local(1), dtf-binary(7), dtf-library(7), dtf-module(7) 15 | -------------------------------------------------------------------------------- /man/dtf-pm.ronn: -------------------------------------------------------------------------------- 1 | dtf-pm(1) -- The dtf package manager 2 | ==================================== 3 | 4 | ## SYNOPSIS 5 | dtf pm [subcommand] [] 6 | 7 | Subcommands: 8 | delete Delete an item from main database. 9 | export Export entire main database to dtf ZIP. 10 | install Install a dtf ZIP or single item. 11 | list List all installed items. 12 | purge Purge all installed items, reset DB. 13 | 14 | ## DESCRIPTION 15 | dtf-pm(1) is the global package manager for dtf(1). It is used to install, remove, and export installed content. There are currently 4 types of content: binaries, libraries, modules, and packages. Additional information about these can be found within: 16 | dtf-binary(7) 17 | dtf-library(7) 18 | dtf-module(7) 19 | dtf-package(7) 20 | 21 | ## EXAMPLES 22 | Installing a single module with auto parsing: 23 | $ dtf pm install --single module --name my_module --auto 24 | 25 | List all installed modules with verbose information: 26 | $ dtf pm list modules -v 27 | 28 | Removing a single module: 29 | $ dtf pm delete --type module --name my_module 30 | 31 | Install a ZIP archive containing content: 32 | $ dtf pm install --zip new_content.zip 33 | 34 | Export all currently installed content to a ZIP: 35 | $ dtf pm export exported.zip 36 | 37 | Removing all globally installed content: 38 | $ dtf pm purge 39 | 40 | ## AUTHOR 41 | Jake Valletta 42 | 43 | ## DTF 44 | Part of the dtf(1) suite. 45 | 46 | ## SEE ALSO 47 | dtf-module(7), dtf-package(7), dtf-library(7), dtf-binary(7) 48 | -------------------------------------------------------------------------------- /man/dtf-project.ronn: -------------------------------------------------------------------------------- 1 | dtf-project(7) -- Information on dtf project structure 2 | ====================================================== 3 | 4 | ## KEY FILES & DIRECTORIES 5 | local_modules/ - The local modules directory contains non-global modules accessible to only the given project. 6 | reports/ - Used by modules to store reports. 7 | .dbs/ - Directory used by modules for database storage. 8 | .dtfini - Property information stored by dtf-prop(1) for the current project. 9 | .dtflog - Saved logs generated by dtf(1) or installed content. 10 | 11 | Generally speaking, properties stored by dtf-prop(1) will reside in either the "Info" or "Local" section. By convention, these should be alphanumeric and '-': 12 | $ dtf prop set Local system-apps "system-apps" 13 | 14 | ## PROJECT LIFECYCLE 15 | Each major software release of a device should have its own project. To create a new project, we use dtf-init(1): 16 | $ mkdir new_project 17 | $ cd new_project 18 | $ dtf init 19 | 20 | This configs any infiguration needed to begin testing your device. At some point, you may want to move on. At this point, you can use dtf-archive(1) to save some space: 21 | $ dtf archive 22 | 23 | You may also want to purge information about your test device (not actual data!) using dtf-reset(1): 24 | $ dtf reset 25 | 26 | ## AUTHOR 27 | Jake Valletta 28 | 29 | ## SEE ALSO 30 | dtf-archive(1), dtf-init(1), dtf-local(1), dtf-prop(1), dtf-reset(1) 31 | -------------------------------------------------------------------------------- /man/dtf-prop.ronn: -------------------------------------------------------------------------------- 1 | dtf-prop(1) -- The dtf property manager 2 | ======================================= 3 | 4 | ## SYNOPSIS 5 | dtf prop [subcommand] [] 6 | 7 | Subcommands: 8 | get [sec] [prop] Get a property. 9 | set [sec] [prop] [val] Set a property. 10 | del [sec] [prop] Delete a property. 11 | dump Dump current properties. 12 | test [sec] [prop] Test if a value is set. 13 | 14 | ## DESCRIPTION 15 | dtf-prop(1) is used to set and get properties for a dtf(1) project. Properties are stored by section. Currently, two sections are utilized: 16 | Info - Information about a device set primarily by dtf(1). 17 | Local - Local directory information used by modules. 18 | 19 | ## EXAMPLES 20 | Set a property in the section Info called serial: 21 | $ dtf prop set Info serial 123456 22 | 23 | Check if a property is set (1 = set, 0 = not set): 24 | $ dtf prop test Info serial 25 | 26 | Get the value of a property: 27 | $ dtf prop get Info sdk 28 | 29 | Delete a property: 30 | $ dtf prop del Info version-string 31 | 32 | Dump all properties: 33 | $ dtf prop dump 34 | 35 | ## AUTHOR 36 | Jake Valletta 37 | 38 | ## DTF 39 | Part of the dtf(1) suite. 40 | 41 | ## SEE ALSO 42 | dtf-project(1) 43 | -------------------------------------------------------------------------------- /man/dtf-reset.ronn: -------------------------------------------------------------------------------- 1 | dtf-reset(1) -- Reset a dtf project's configuration 2 | =================================================== 3 | 4 | ## SYNOPSIS 5 | dtf reset 6 | 7 | ## DESCRIPTION 8 | dtf-reset(1) is used to remove the dtf(1) configuration for a given project. It is not reversible. 9 | 10 | ## EXAMPLES 11 | dtf-reset(1) does not take any arguments, and does not have any subcommands. To remove the dtf(1) configuration file for the current project: 12 | 13 | $ cd old_project 14 | $ dtf reset 15 | 16 | Note: this does not remove project data. It only removes data contained in dtf(1) configuration file. 17 | 18 | ## AUTHOR 19 | Jake Valletta 20 | 21 | ## DTF 22 | Part of the dtf(1) suite. 23 | -------------------------------------------------------------------------------- /man/dtf-status.ronn: -------------------------------------------------------------------------------- 1 | dtf-status(1) -- Determine if a project device is connected 2 | =========================================================== 3 | 4 | ## SYNOPSIS 5 | dtf status 6 | 7 | ## DESCRIPTION 8 | dtf-status(1) prints whether or not a project device is connected. 9 | 10 | ## EXAMPLES 11 | dtf-status(1) does not take any arguments, and does not have any subcommands. To print the status of a connected device: 12 | $ cd my_project 13 | $ dtf status 14 | 15 | ## AUTHOR 16 | Jake Valletta 17 | 18 | ## DTF 19 | Part of the dtf(1) suite. 20 | -------------------------------------------------------------------------------- /man/dtf-upgrade.ronn: -------------------------------------------------------------------------------- 1 | dtf-uograde(1) -- Update components of dtf(1) 2 | ============================================= 3 | 4 | ## SYNOPSIS 5 | dtf upgrade [subcommand] [] 6 | 7 | Subcommands: 8 | core Update dtf framework. 9 | included Update just the bundled TAR. 10 | 11 | ## DESCRIPTION 12 | dtf-upgrade(1) is used to keep dtf(1) up-to-date. 13 | 14 | ## EXAMPLES 15 | Update the included TAR and reconfigure dtf(1)'s bindings: 16 | $ dtf upgrade included 17 | 18 | Download the install/upgrade script to update dtf(1): 19 | $ dtf upgrade core 20 | 21 | ## AUTHOR 22 | Jake Valletta 23 | 24 | ## DTF 25 | Part of the dtf(1) suite. 26 | -------------------------------------------------------------------------------- /man/dtf.ronn: -------------------------------------------------------------------------------- 1 | dtf(1) -- Module-based framework for discovering vulnerabilities on Android devices 2 | =================================================================================== 3 | 4 | ## SYNOPSIS 5 | _dtf_ [module|command] [] 6 | 7 | 8 | ## DESCRIPTION 9 | dtf(1) is a module-based framework that enables a user to interact with an Android device and discover vulnerabilities. Some features provided by dtf(1) are: 10 | 11 | 1. Package management 12 | 2. Project property subsystem 13 | 3. Client application to interface with Android device 14 | 4. Python APIs to interact with a Android device 15 | 5. Bindings to incorporate with existing Android tools 16 | 17 | ## EXAMPLES 18 | Run the module **apkget** with arguments "-p" and "com.android.mms": 19 | 20 | $ dtf apkget -p com.android.mms 21 | 22 | Run the built-in package manager and list installed modules: 23 | 24 | $ dtf pm list modules 25 | 26 | For examples of built-in commands, see the section [SEE ALSO][]. 27 | 28 | ## ENVIRONMENT VARIABLES 29 | _GLOG_LEVEL_ - Manually specify a module's logging level. Valid levels are 0 (no logging) - 5 (full). 30 | 31 | ## AUTHOR 32 | Jake Valletta 33 | 34 | ## COPYRIGHT 35 | dtf(1) is copyright (c) 2013-2017, Jake Valletta (@jake_valletta). Released under the Apache License, Version 2.0. 36 | license. 37 | 38 | ## SEE ALSO 39 | dtf-archive(1), dtf-binding(1), dtf-client(1), dtf-init(1), dtf-local(1), dtf-pm(1), dtf-prop(1), dtf-reset(1), dtf-status(1), dtf-upgrade(1), dtf-check(1), dtf-project(7), dtf-binary(7), dtf-library(7), dtf-module(7), dtf-package(7) 40 | -------------------------------------------------------------------------------- /python-dtf/.coveragerc: -------------------------------------------------------------------------------- 1 | [run] 2 | branch = True 3 | parallel = True 4 | concurrency = multiprocessing 5 | source = dtf/ 6 | -------------------------------------------------------------------------------- /python-dtf/.gitignore: -------------------------------------------------------------------------------- 1 | dtf/VERSION 2 | 3 | # Byte-compiled / optimized / DLL files 4 | __pycache__/ 5 | *.py[cod] 6 | *$py.class 7 | 8 | # Distribution / packaging 9 | .Python 10 | env/ 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | *.egg-info/ 23 | .installed.cfg 24 | *.egg 25 | .gradle 26 | 27 | # Coverage 28 | .coverage 29 | .cache 30 | htmlcov 31 | # virtualenv stuff 32 | venv/ 33 | -------------------------------------------------------------------------------- /python-dtf/MANIFEST.in: -------------------------------------------------------------------------------- 1 | include dtf/VERSION 2 | -------------------------------------------------------------------------------- /python-dtf/README.rst: -------------------------------------------------------------------------------- 1 | Android Device Testing Framework (dtf) 2 | ====================================== 3 | 4 | About 5 | ----- 6 | The Android Device Testing Framework ("dtf") is a data collection and analysis framework to help individuals answer the question: "Where are the vulnerabilities on this mobile device?" Dtf provides a modular approach and built-in APIs that allows testers to quickly create scripts to interact with their Android devices. By default, dtf does not include any modules, but a collection of testing modules is made available on the [Cobra Den website](www.thecobraden.com/projects/dtf/). These modules allow testers to obtain information from their Android device, process this information into databases, and then start searching for vulnerabilities (all without requiring root privileges). These modules help you focus on changes made to AOSP components such as applications, frameworks, system services, as well as lower-level components such as binaries, libraries, and device drivers. In addition, you'll be able to analyze new functionality implemented by the OEMs and other parties to find vulnerabilities. 7 | -------------------------------------------------------------------------------- /python-dtf/dtf/__init__.py: -------------------------------------------------------------------------------- 1 | """Main dtf Module""" 2 | 3 | from __future__ import absolute_import 4 | import pkg_resources 5 | 6 | # Here we use the installed version as version number. For tests, 7 | # this may not exist so we just fake it and return unknown. 8 | # pylint: disable=maybe-no-member 9 | try: 10 | __version__ = pkg_resources.get_distribution('dtf').version 11 | except pkg_resources.DistributionNotFound: 12 | __version__ = "???" 13 | -------------------------------------------------------------------------------- /python-dtf/dtf/colors.py: -------------------------------------------------------------------------------- 1 | # Android Device Testing Framework ("dtf") 2 | # Copyright 2013-2016 Jake Valletta (@jake_valletta) 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | """Wrapper API for using colors in dtf modules""" 17 | 18 | from __future__ import absolute_import 19 | from colored import fg, attr 20 | 21 | import dtf.globals as glbl 22 | 23 | COLOR_ERR = fg(1) 24 | COLOR_WARN = fg(3) 25 | COLOR_INFO = fg(2) 26 | COLOR_VERB = fg(6) 27 | COLOR_DEB = fg(5) 28 | 29 | 30 | def __use_colors(): 31 | 32 | """Check if colors should be used""" 33 | 34 | return bool(glbl.get_generic_global('Config', 'use_colors') == '1') 35 | 36 | 37 | def error(message): 38 | 39 | """Color format a message for errors""" 40 | 41 | if __use_colors(): 42 | return "%s%s%s" % (COLOR_ERR, message, attr(0)) 43 | else: 44 | return message 45 | 46 | 47 | def warning(message): 48 | 49 | """Color format a message for warnings""" 50 | 51 | if __use_colors(): 52 | return "%s%s%s" % (COLOR_WARN, message, attr(0)) 53 | else: 54 | return message 55 | 56 | 57 | def info(message): 58 | 59 | """Color format a message for informational messages""" 60 | 61 | if __use_colors(): 62 | return "%s%s%s" % (COLOR_INFO, message, attr(0)) 63 | else: 64 | return message 65 | 66 | 67 | def verbose(message): 68 | 69 | """Color format a message for verbose messages""" 70 | 71 | if __use_colors(): 72 | return "%s%s%s" % (COLOR_VERB, message, attr(0)) 73 | else: 74 | return message 75 | 76 | 77 | def debug(message): 78 | 79 | """Color format a message for debugging""" 80 | 81 | if __use_colors(): 82 | return "%s%s%s" % (COLOR_DEB, message, attr(0)) 83 | else: 84 | return message 85 | 86 | 87 | def bold(message): 88 | 89 | """Format a bold message""" 90 | 91 | if __use_colors(): 92 | return "%s%s%s" % (attr('bold'), message, attr(0)) 93 | else: 94 | return message 95 | -------------------------------------------------------------------------------- /python-dtf/dtf/constants.py: -------------------------------------------------------------------------------- 1 | # Android Device Testing Framework ("dtf") 2 | # Copyright 2013-2015 Jake Valletta (@jake_valletta) 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | """dtf Constants""" 17 | 18 | from __future__ import absolute_import 19 | import dtf 20 | 21 | VERSION = dtf.__version__ 22 | 23 | DTF_CLIENT = "com.dtf.client" 24 | 25 | # API Constants 26 | API_1 = 1 27 | API_2 = 2 28 | API_CUPCAKE = 3 29 | API_DONUT = 4 30 | API_ECLAIR = 5 31 | API_ECLAIR_R1 = 6 32 | API_ECLAIR_R2 = 7 33 | API_FROYO = 8 34 | API_GINGERBREAD = 9 35 | API_GINGERBREAD_R1 = 10 36 | API_HONEYCOMB = 11 37 | API_HONEYCOMB_R1 = 12 38 | API_HONEYCOMB_R2 = 13 39 | API_ICE_CREAM_SANDWICH = 14 40 | API_ICE_CREAM_SANDWICH_R1 = 15 41 | API_JELLY_BEAN = 16 42 | API_JELLY_BEAN_R1 = 17 43 | API_JELLY_BEAN_R2 = 18 44 | API_KITKAT = 19 45 | API_WEAR = 20 46 | API_LOLLIPOP = 21 47 | API_LOLLIPOP_R1 = 22 48 | API_MARSHMALLOW = 23 49 | API_NOUGAT = 24 50 | API_NOUGAT_R1 = 25 51 | 52 | # Max Supported 53 | API_MAX = API_NOUGAT_R1 54 | -------------------------------------------------------------------------------- /python-dtf/dtf/core/__init__.py: -------------------------------------------------------------------------------- 1 | """Core (internal) dtf functionality""" 2 | -------------------------------------------------------------------------------- /python-dtf/dtf/core/cmds/__init__.py: -------------------------------------------------------------------------------- 1 | """Built-in dtf commands""" 2 | -------------------------------------------------------------------------------- /python-dtf/dtf/core/cmds/archive.py: -------------------------------------------------------------------------------- 1 | # Android Device Testing Framework ("dtf") 2 | # Copyright 2013-2015 Jake Valletta (@jake_valletta) 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | """Built-in module for archiving a project""" 17 | 18 | from __future__ import absolute_import 19 | from __future__ import print_function 20 | import os 21 | import zipfile 22 | 23 | import dtf.properties as prop 24 | import dtf.logging as log 25 | from dtf.module import Module 26 | 27 | 28 | class archive(Module): # pylint: disable=invalid-name 29 | 30 | """Module class for archiving a project""" 31 | 32 | @classmethod 33 | def usage(cls): 34 | 35 | """Module usage""" 36 | 37 | print('dtf Archiver') 38 | print('') 39 | print('Subcommands:') 40 | print(' create Archive the current project.') 41 | print('') 42 | 43 | return 0 44 | 45 | def make_zip(self, zip_name): 46 | 47 | """Make a ZIP file""" 48 | 49 | zip_f = None 50 | 51 | try: 52 | zip_f = zipfile.ZipFile(zip_name, 'w', zipfile.ZIP_DEFLATED) 53 | except RuntimeError: 54 | log.e(self.name, "ZIP_DEFLATE not available!") 55 | return -1 56 | 57 | # pylint: disable=unused-variable 58 | for root, dirs, files in os.walk(os.getcwd()): 59 | for file_to_add in files: 60 | zip_f.write(os.path.join(root, file_to_add)) 61 | 62 | zip_f.close() 63 | 64 | return 0 65 | 66 | def do_create(self, args): 67 | 68 | """Create the archive""" 69 | 70 | zip_name = "" 71 | 72 | if len(args) == 0: 73 | zip_name = "%s.zip" % prop.get_prop('Info', 'version-string') 74 | 75 | else: 76 | zip_name = args.pop() 77 | 78 | log.i(self.name, "Archiving to '%s'..." % zip_name) 79 | 80 | rtn = self.make_zip(zip_name) 81 | 82 | if rtn != 0: 83 | log.e(self.name, "Unable to archive project!") 84 | 85 | return rtn 86 | 87 | def execute(self, args): 88 | 89 | """Main module executor""" 90 | 91 | self.name = self.__self__ 92 | 93 | rtn = 0 94 | 95 | if len(args) < 1: 96 | return self.usage() 97 | 98 | sub_cmd = args.pop(0) 99 | 100 | if sub_cmd == 'create': 101 | rtn = self.do_create(args) 102 | 103 | else: 104 | print("Sub-command '%s' not found!" % sub_cmd) 105 | rtn = self.usage() 106 | 107 | return rtn 108 | -------------------------------------------------------------------------------- /python-dtf/dtf/core/cmds/binding.py: -------------------------------------------------------------------------------- 1 | # Android Device Testing Framework ("dtf") 2 | # Copyright 2013-2015 Jake Valletta (@jake_valletta) 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | """Built-in module for getting a binding path""" 17 | 18 | from __future__ import absolute_import 19 | from __future__ import print_function 20 | from dtf.globals import get_all_bindings, get_binding, GlobalPropertyError 21 | from dtf.module import Module 22 | import dtf.logging as log 23 | 24 | TAG = "binding" 25 | 26 | 27 | class binding(Module): # pylint: disable=invalid-name 28 | 29 | """Module class for listing local modules""" 30 | 31 | @classmethod 32 | def do_print_all(cls): 33 | 34 | """Print all bindings""" 35 | 36 | try: 37 | for bind_key, value in get_all_bindings(): 38 | if bind_key.startswith('dtf_'): 39 | print("%s : %s" % (bind_key, value)) 40 | except GlobalPropertyError: 41 | log.e(TAG, "Unable to list bindings!") 42 | return -1 43 | 44 | return 0 45 | 46 | @classmethod 47 | def do_print_binding(cls, bind_key): 48 | 49 | """Print a single binding""" 50 | 51 | try: 52 | print(get_binding(bind_key)) 53 | except GlobalPropertyError: 54 | log.e(TAG, "Unable to find binding: %s" % bind_key) 55 | return -1 56 | 57 | return 0 58 | 59 | def execute(self, args): 60 | 61 | """Main module executor""" 62 | 63 | if len(args) == 0: 64 | return self.do_print_all() 65 | else: 66 | return self.do_print_binding(args[0]) 67 | -------------------------------------------------------------------------------- /python-dtf/dtf/core/cmds/local.py: -------------------------------------------------------------------------------- 1 | # Android Device Testing Framework ("dtf") 2 | # Copyright 2013-2015 Jake Valletta (@jake_valletta) 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | """Built-in module for listing local modules""" 17 | 18 | from __future__ import absolute_import 19 | from __future__ import print_function 20 | from os import listdir 21 | from os.path import isfile, join 22 | 23 | import dtf.core.utils as utils 24 | from dtf.module import Module 25 | 26 | 27 | class local(Module): # pylint: disable=invalid-name 28 | 29 | """Module class for listing local modules""" 30 | 31 | @classmethod 32 | def get_locals(cls): 33 | 34 | """List local modules directory""" 35 | 36 | local_path = "%s/%s" % (utils.get_project_root(), 37 | utils.LOCAL_MODULES_DIRECTORY) 38 | 39 | return [f for f in listdir(local_path) if isfile(join(local_path, f))] 40 | 41 | def execute(self, args): # pylint: disable=unused-argument 42 | 43 | """Main module executor""" 44 | 45 | print('Local Modules:') 46 | 47 | for l_module in self.get_locals(): 48 | 49 | print(" %s" % l_module) 50 | 51 | return 0 52 | -------------------------------------------------------------------------------- /python-dtf/dtf/core/cmds/prop.py: -------------------------------------------------------------------------------- 1 | # Android Device Testing Framework ("dtf") 2 | # Copyright 2013-2015 Jake Valletta (@jake_valletta) 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | """Built-in module for handling project properties""" 17 | 18 | from __future__ import absolute_import 19 | from __future__ import print_function 20 | 21 | import configparser 22 | 23 | from dtf.module import Module 24 | import dtf.logging as log 25 | import dtf.core.utils as utils 26 | 27 | from dtf.properties import (get_prop, set_prop, del_prop, 28 | test_prop, PropertyError) 29 | 30 | 31 | class prop(Module): # pylint: disable=invalid-name 32 | 33 | """Module class for property management""" 34 | 35 | @classmethod 36 | def usage(cls): 37 | 38 | """Display module usage""" 39 | 40 | print('dtf Property Manager') 41 | print('Subcommands:') 42 | print(' get [sec] [prop] Get a property.') 43 | print(' set [sec] [prop] [val] Set a property.') 44 | print(' del [sec] [prop] Delete a property.') 45 | print(' dump Dump current properties.') 46 | print(' test [sec] [prop] Test if a value is set.') 47 | print('') 48 | 49 | return 0 50 | 51 | def do_get(self, args): 52 | 53 | """Get a property""" 54 | 55 | rtn = 0 56 | value = "" 57 | 58 | if len(args) != 2: 59 | log.e(self.name, "A section and property must be specified.") 60 | rtn = self.usage() 61 | 62 | else: 63 | section = args[0] 64 | prop_name = args[1] 65 | 66 | try: 67 | value = get_prop(section, prop_name) 68 | 69 | except PropertyError: 70 | rtn = -1 71 | 72 | print(value) 73 | 74 | return rtn 75 | 76 | def do_set(self, args): 77 | 78 | """Set a property""" 79 | 80 | rtn = 0 81 | 82 | if len(args) < 3: 83 | log.e(self.name, "A section, prop, and value must be specified.") 84 | rtn = self.usage() 85 | 86 | else: 87 | section = args[0] 88 | prop_name = args[1] 89 | value = " ".join(args[2:]) 90 | 91 | rtn = set_prop(section, prop_name, value) 92 | 93 | return rtn 94 | 95 | def do_del(self, args): 96 | 97 | """Delete a property""" 98 | 99 | rtn = 0 100 | 101 | if len(args) != 2: 102 | log.e(self.name, "A section and property must be specified.") 103 | rtn = self.usage() 104 | 105 | else: 106 | section = args[0] 107 | prop_name = args[1] 108 | 109 | rtn = del_prop(section, prop_name) 110 | 111 | return rtn 112 | 113 | @classmethod 114 | def do_dump(cls): 115 | 116 | """Dump entire configuration""" 117 | 118 | config = configparser.ConfigParser() 119 | config.read(utils.CONFIG_FILE_NAME) 120 | 121 | for section in config.sections(): 122 | print("[%s]" % section) 123 | for name, value in config.items(section): 124 | print("%s = %s" % (name, value)) 125 | 126 | print('') 127 | 128 | return 0 129 | 130 | def do_test(self, args): 131 | 132 | """Test if a value is set or not""" 133 | 134 | rtn = 0 135 | 136 | if len(args) != 2: 137 | log.e(self.name, "A section and property must be specified.") 138 | rtn = self.usage() 139 | 140 | else: 141 | section = args[0] 142 | prop_name = args[1] 143 | 144 | rtn = test_prop(section, prop_name) 145 | 146 | return rtn 147 | 148 | def execute(self, args): 149 | 150 | """Main module executor""" 151 | 152 | self.name = self.__self__ 153 | 154 | rtn = 0 155 | 156 | if len(args) < 1: 157 | return self.usage() 158 | 159 | sub_cmd = args.pop(0) 160 | 161 | if sub_cmd == 'get': 162 | rtn = self.do_get(args) 163 | 164 | elif sub_cmd == 'set': 165 | rtn = self.do_set(args) 166 | 167 | elif sub_cmd == 'del': 168 | rtn = self.do_del(args) 169 | 170 | elif sub_cmd == 'dump': 171 | rtn = self.do_dump() 172 | 173 | elif sub_cmd == 'test': 174 | rtn = self.do_test(args) 175 | 176 | else: 177 | print("Sub-command '%s' not found!" % sub_cmd) 178 | rtn = self.usage() 179 | 180 | return rtn 181 | -------------------------------------------------------------------------------- /python-dtf/dtf/core/cmds/reset.py: -------------------------------------------------------------------------------- 1 | # Android Device Testing Framework ("dtf") 2 | # Copyright 2013-2015 Jake Valletta (@jake_valletta) 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | """Built-in module for reseting a project""" 17 | 18 | from __future__ import absolute_import 19 | from __future__ import print_function 20 | import os 21 | 22 | import dtf.core.compat as compat 23 | import dtf.core.utils as utils 24 | import dtf.logging as log 25 | 26 | from dtf.module import Module 27 | 28 | TAG = 'reset' 29 | 30 | 31 | class reset(Module): # pylint: disable=invalid-name 32 | 33 | """Module class for reseting a project""" 34 | 35 | def execute(self, args): # pylint: disable=unused-argument,no-self-use 36 | 37 | """Main module executor""" 38 | 39 | print('Are you sure you want to delete the dtf project in this ' 40 | 'directory? This cannot be reversed! [y/N]', end=" ") 41 | 42 | inp = compat.raw_input() 43 | 44 | if inp.lower() == 'y': 45 | os.remove(utils.CONFIG_FILE_NAME) 46 | log.i(TAG, "Reset complete!") 47 | return 0 48 | else: 49 | log.w(TAG, "Reset aborted.") 50 | return -1 51 | -------------------------------------------------------------------------------- /python-dtf/dtf/core/cmds/status.py: -------------------------------------------------------------------------------- 1 | # Android Device Testing Framework ("dtf") 2 | # Copyright 2013-2015 Jake Valletta (@jake_valletta) 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | """Built-in module for getting the status of a project""" 17 | 18 | from __future__ import absolute_import 19 | from __future__ import print_function 20 | 21 | from dtf.module import Module 22 | import dtf.adb as DtfAdb 23 | 24 | 25 | class status(Module): # pylint: disable=invalid-name 26 | 27 | """Module class for getting the status of a device""" 28 | 29 | adb = DtfAdb.DtfAdb() 30 | 31 | def execute(self, args): # pylint: disable=unused-argument 32 | 33 | """Main module executor""" 34 | 35 | found = False 36 | 37 | serial = DtfAdb.get_mode_serial() 38 | devices = self.adb.get_devices() 39 | 40 | for device in devices: 41 | if device['serial'] == serial: 42 | found = True 43 | break 44 | 45 | print("Status:", end=" ") 46 | 47 | if found: 48 | print('Connected') 49 | else: 50 | print('Not Connected') 51 | 52 | print("Serial Number: %s" % serial) 53 | 54 | return 0 55 | -------------------------------------------------------------------------------- /python-dtf/dtf/core/cmds/upgrade.py: -------------------------------------------------------------------------------- 1 | # Android Device Testing Framework ("dtf") 2 | # Copyright 2013-2017 Jake Valletta (@jake_valletta) 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | """Built-in module for archiving a project""" 17 | 18 | from __future__ import absolute_import 19 | from __future__ import print_function 20 | 21 | import tempfile 22 | from argparse import ArgumentParser 23 | 24 | import requests 25 | 26 | import dtf.core.autoconfig as autoconfig 27 | import dtf.module as module 28 | import dtf.logging as log 29 | 30 | BRANCH_DEFAULT = 'master' 31 | UPGRADE_SCRIPT_TEMPLATE = ("https://raw.githubusercontent.com/android-dtf/" 32 | "dtf/%s/installscript/install.sh") 33 | 34 | UPGRADE_TAR_TEMPLATE = ("https://raw.githubusercontent.com/android-dtf/" 35 | "dtf/%s/dtf-included/build/included.tar") 36 | 37 | 38 | class upgrade(module.Module): # pylint: disable=invalid-name 39 | 40 | """Module class for performing updates""" 41 | 42 | @classmethod 43 | def usage(cls): 44 | 45 | """Display module usage""" 46 | 47 | print('dtf Client Manager') 48 | print('Subcommands:') 49 | print(' core Update dtf framework.') 50 | print(' included Update just the bundled TAR.') 51 | print('') 52 | 53 | return 0 54 | 55 | def __download_file(self, url, file_name): 56 | 57 | """Download a file from URL to tempfile""" 58 | 59 | try: 60 | req = requests.get(url, verify=True, stream=True, 61 | allow_redirects=True) 62 | 63 | except requests.exceptions.RequestException as excpt: 64 | 65 | log.e(self.name, "Error pulling update script!") 66 | print(excpt) 67 | return None 68 | 69 | if not req.ok: 70 | return None 71 | 72 | temp_file_name = "%s/%s" % (tempfile.gettempdir(), file_name) 73 | 74 | temp_f = open(temp_file_name, "wb") 75 | 76 | for chunk in req.iter_content(chunk_size=1024): 77 | if chunk: 78 | temp_f.write(chunk) 79 | 80 | # Reset the seek 81 | temp_f.close() 82 | 83 | return temp_file_name 84 | 85 | def do_core_upgrade(self, args): 86 | 87 | """Perform upgrade of dtf""" 88 | 89 | parser = ArgumentParser(prog='upgrade core', 90 | description='Update dtf framework.') 91 | parser.add_argument('--reconfigure', action='store_true', 92 | help="Just reconfig (post upgrade).") 93 | parser.add_argument('--branch', dest='branch', 94 | default=BRANCH_DEFAULT, 95 | help="Specify the branch to pull from.") 96 | parsed_args = parser.parse_args(args) 97 | 98 | # First, is this just a reconfig? 99 | if parsed_args.reconfigure: 100 | log.i(self.name, "Performing reconfiguration...") 101 | return autoconfig.initialize_from_local(is_full=True) 102 | 103 | log.i(self.name, "Downloading update script...") 104 | 105 | upgrade_script_url = UPGRADE_SCRIPT_TEMPLATE % parsed_args.branch 106 | 107 | upgrade_script_name = self.__download_file(upgrade_script_url, 108 | 'dtf_upgrade.sh') 109 | if upgrade_script_name is None: 110 | log.e(self.name, "Unable to download: %s" % upgrade_script_url) 111 | return -1 112 | 113 | log.i(self.name, "Update script downloaded. To complete install run:") 114 | log.i(self.name, " chmod u+x %s" % upgrade_script_name) 115 | log.i(self.name, " %s" % upgrade_script_name) 116 | 117 | return 0 118 | 119 | def do_included_upgrade(self, args): 120 | 121 | """Perform upgrade of only included""" 122 | 123 | parser = ArgumentParser(prog='upgrade included', 124 | description='Update the bundled TAR.') 125 | parser.add_argument('--branch', dest='branch', 126 | default=BRANCH_DEFAULT, 127 | help="Specify the branch to pull from.") 128 | 129 | parsed_args = parser.parse_args(args) 130 | 131 | log.i(self.name, "Performing included upgrade...") 132 | 133 | upgrade_tar_url = UPGRADE_TAR_TEMPLATE % parsed_args.branch 134 | 135 | # First pull 136 | tar_name = self.__download_file(upgrade_tar_url, 'dtf_included.tar') 137 | if tar_name is None: 138 | log.e(self.name, "Unable to download: %s" % upgrade_tar_url) 139 | return -1 140 | 141 | # Now we perform the reconfiguration 142 | return autoconfig.initialize_from_tar(tar_name, is_full=False, 143 | clean_up=True) 144 | 145 | def execute(self, args): 146 | 147 | """Main module executor""" 148 | 149 | self.name = self.__self__ 150 | 151 | rtn = 0 152 | 153 | if len(args) < 1: 154 | return self.usage() 155 | 156 | sub_cmd = args.pop(0) 157 | 158 | if sub_cmd == 'core': 159 | rtn = self.do_core_upgrade(args) 160 | 161 | elif sub_cmd == 'included': 162 | rtn = self.do_included_upgrade(args) 163 | 164 | else: 165 | print("Sub-command '%s' not found!" % sub_cmd) 166 | rtn = self.usage() 167 | 168 | return rtn 169 | -------------------------------------------------------------------------------- /python-dtf/dtf/core/compat.py: -------------------------------------------------------------------------------- 1 | # Android Device Testing Framework ("dtf") 2 | # Copyright 2013-2017 Jake Valletta (@jake_valletta) 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | """Compatibility helpers""" 17 | 18 | # pylint: disable=invalid-name,input-builtin,raw_input-builtin 19 | # pylint: disable=wrong-import-position 20 | 21 | from __future__ import absolute_import 22 | 23 | try: 24 | raw_input = raw_input # pylint: disable=redefined-builtin 25 | except NameError: 26 | raw_input = input 27 | 28 | try: 29 | from io import StringIO 30 | except ImportError: 31 | from cStringIO import StringIO 32 | 33 | StringIO = StringIO 34 | 35 | try: 36 | import urlparse 37 | except ImportError: 38 | # pylint: disable=no-name-in-module,import-error 39 | import urllib.parse as urlparse 40 | 41 | urlparse = urlparse 42 | -------------------------------------------------------------------------------- /python-dtf/dtf/core/item.py: -------------------------------------------------------------------------------- 1 | # Android Device Testing Framework ("dtf") 2 | # Copyright 2013-2017 Jake Valletta (@jake_valletta) 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | """Item class""" 17 | 18 | # Eventually this will be changed 19 | # pylint: disable=too-many-instance-attributes 20 | 21 | from __future__ import absolute_import 22 | import semantic_version 23 | 24 | TYPE_MODULE = 'module' 25 | TYPE_LIBRARY = 'library' 26 | TYPE_BINARY = 'binary' 27 | TYPE_PACKAGE = 'package' 28 | 29 | VALID_TYPES = [TYPE_BINARY, TYPE_LIBRARY, 30 | TYPE_MODULE, TYPE_PACKAGE] 31 | 32 | 33 | def is_valid_version(version_string): 34 | 35 | """Check if version string is correct""" 36 | 37 | try: 38 | semantic_version.Version(version_string) 39 | except ValueError: 40 | return False 41 | 42 | return True 43 | 44 | 45 | def item_is_newer(installed_item, item): 46 | 47 | """Determine if an item is newer""" 48 | 49 | return bool(semantic_version.Version(installed_item.version) < 50 | semantic_version.Version(item.version)) 51 | 52 | 53 | class Item(object): # pylint: disable=too-few-public-methods 54 | 55 | """Class for working with content""" 56 | 57 | install_name = None 58 | local_name = None 59 | name = None 60 | type = type 61 | author = None 62 | about = None 63 | version = None 64 | 65 | def __init__(self): 66 | 67 | """Initialize new object""" 68 | 69 | self.install_name = None 70 | self.local_name = None 71 | self.name = None 72 | self.type = None 73 | self.author = None 74 | self.about = None 75 | self.version = None 76 | 77 | def __repr__(self): 78 | 79 | """Tostring for item""" 80 | 81 | temp = "Name: %s (%s)\n" % (self.name, self.type) 82 | if self.type == TYPE_MODULE: 83 | temp += " About: %s\n" % self.about 84 | temp += " Installs as: %s\n" % self.install_name 85 | temp += " Author: %s\n" % self.author 86 | temp += " Version: %s\n" % self.version 87 | return temp 88 | -------------------------------------------------------------------------------- /python-dtf/dtf/core/utils.py: -------------------------------------------------------------------------------- 1 | # Android Device Testing Framework ("dtf") 2 | # Copyright 2013-2015 Jake Valletta (@jake_valletta) 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | """ dtf Utilities """ 17 | 18 | from __future__ import absolute_import 19 | from hashlib import md5 20 | import errno 21 | import os 22 | import os.path 23 | import shutil 24 | import stat 25 | 26 | import dtf.core.compat as compat 27 | 28 | CONFIG_FILE_NAME = '.dtfini' 29 | LOG_FILE_NAME = '.dtflog' 30 | 31 | REPORTS_DIRECTORY = 'reports' 32 | DBS_DIRECTORY = '.dbs' 33 | LOCAL_MODULES_DIRECTORY = 'local_modules' 34 | 35 | TAG = 'dtf-utils' 36 | 37 | 38 | def __upsearch(file_name, dir_name): 39 | 40 | """Recursively find a file, searching up.""" 41 | 42 | if os.path.isfile("%s/%s" % (dir_name, file_name)): 43 | return dir_name 44 | else: 45 | new_dir = os.path.abspath(os.path.join(dir_name, os.pardir)) 46 | if dir_name == new_dir: 47 | return None 48 | return __upsearch(file_name, new_dir) 49 | 50 | 51 | def get_project_root(): 52 | 53 | """Search for and return the dtf project root.""" 54 | 55 | return __upsearch(CONFIG_FILE_NAME, os.getcwd()) 56 | 57 | 58 | def get_pydtf_dir(): 59 | 60 | """Return the location of the dtf dist-packages directory.""" 61 | 62 | return os.path.dirname(os.path.split(os.path.abspath(__file__))[0]) 63 | 64 | 65 | def get_dtf_data_dir(): 66 | 67 | """Return the location of the dtf data directory.""" 68 | 69 | return os.path.expanduser('~') + '/.dtf' 70 | 71 | 72 | def get_dtf_lib_dir(): 73 | 74 | """Return the location of the dtf lib dir.""" 75 | 76 | return "/usr/local/lib/android-dtf" 77 | 78 | 79 | def md5_local(file_path): 80 | 81 | """MD5 a local file""" 82 | 83 | file_f = open(file_path, 'rb') 84 | 85 | local_m = md5() 86 | while True: 87 | data = file_f.read(128) 88 | if not data: 89 | break 90 | local_m.update(data) 91 | 92 | return local_m.hexdigest() 93 | 94 | 95 | def is_exe(fpath): 96 | 97 | """ Check if file is an executable""" 98 | 99 | # stackoverflow.com/questions/377017/test-if-executable-exists-in-python 100 | return os.path.isfile(fpath) and os.access(fpath, os.X_OK) 101 | 102 | 103 | def which(program): 104 | 105 | """Test if program is pathed.""" 106 | 107 | # stackoverflow.com/questions/377017/test-if-executable-exists-in-python 108 | 109 | fpath = os.path.split(program)[0] 110 | 111 | if fpath: 112 | if is_exe(program): 113 | return program 114 | else: 115 | for path in os.environ["PATH"].split(os.pathsep): 116 | path = path.strip('"') 117 | exe_file = os.path.join(path, program) 118 | if is_exe(exe_file): 119 | return exe_file 120 | 121 | return None 122 | 123 | 124 | def is_executable(file_name): 125 | 126 | """Check if a file can be executed""" 127 | 128 | return bool(stat.S_IXUSR & os.stat(file_name)[stat.ST_MODE]) 129 | 130 | 131 | def mkdir_recursive(path): 132 | 133 | """Recursively create a directory""" 134 | 135 | try: 136 | os.makedirs(path) 137 | except OSError as exc: # Python >2.5 138 | if exc.errno == errno.EEXIST and os.path.isdir(path): 139 | pass 140 | else: 141 | raise 142 | 143 | 144 | # http://stackoverflow.com/questions/1158076/implement-touch-using-python 145 | def touch(file_name, times=None): 146 | 147 | """Touch a file""" 148 | 149 | with open(file_name, 'a'): 150 | os.utime(file_name, times) 151 | 152 | 153 | def delete_file(file_name): 154 | 155 | """Delete a file (show errors optional)""" 156 | 157 | try: 158 | os.remove(file_name) 159 | except OSError: 160 | pass 161 | 162 | return 0 163 | 164 | 165 | def delete_tree(directory_name): 166 | 167 | """Delete a directory recursively""" 168 | 169 | try: 170 | shutil.rmtree(directory_name) 171 | except OSError: 172 | pass 173 | 174 | return 0 175 | 176 | 177 | def file_in_zip(zip_f, file_name): 178 | 179 | """Determine if a file exists in a ZIP""" 180 | 181 | try: 182 | zip_f.read(file_name) 183 | return True 184 | except KeyError: 185 | return False 186 | 187 | 188 | def directory_in_zip(zip_f, directory_name): 189 | 190 | """Determine if a directory exists in a ZIP""" 191 | 192 | return any(x.startswith("%s/" % directory_name.rstrip("/")) 193 | for x in zip_f.namelist()) 194 | 195 | 196 | def is_valid_url(url_string): 197 | 198 | """Test and return valid URL""" 199 | 200 | parsed_url = compat.urlparse.urlparse(url_string) 201 | 202 | return bool(parsed_url.scheme) 203 | 204 | 205 | def is_http_url(url_string): 206 | 207 | """Check scheme of a URL""" 208 | 209 | return bool(compat.urlparse.urlparse(url_string).scheme == 'http') 210 | -------------------------------------------------------------------------------- /python-dtf/dtf/exceptions.py: -------------------------------------------------------------------------------- 1 | # Android Device Testing Framework ("dtf") 2 | # Copyright 2013-2017 Jake Valletta (@jake_valletta) 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | """dtf Exceptions""" 17 | 18 | from __future__ import absolute_import 19 | 20 | 21 | class DtfException(Exception): # pylint: disable=too-few-public-methods 22 | 23 | """Generic dtf Exceptions""" 24 | 25 | def __init__(self, message): 26 | 27 | """Raise new exception""" 28 | 29 | # Call the base class constructor with the parameters it needs 30 | Exception.__init__(self, message) 31 | -------------------------------------------------------------------------------- /python-dtf/dtf/globals.py: -------------------------------------------------------------------------------- 1 | # Android Device Testing Framework ("dtf") 2 | # Copyright 2013-2015 Jake Valletta (@jake_valletta) 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | """Global dtf locations""" 17 | 18 | from __future__ import absolute_import 19 | from __future__ import print_function 20 | import os.path 21 | import configparser 22 | 23 | import dtf.core.utils as utils 24 | 25 | DTF_DATA_DIR = utils.get_dtf_data_dir() 26 | DTF_BINARIES_DIR = DTF_DATA_DIR + "/binaries/" 27 | DTF_LIBRARIES_DIR = DTF_DATA_DIR + "/libraries/" 28 | DTF_MODULES_DIR = DTF_DATA_DIR + "/modules/" 29 | DTF_PACKAGES_DIR = DTF_DATA_DIR + "/packages/" 30 | DTF_DB = DTF_DATA_DIR + "/main.db" 31 | 32 | DTF_INCLUDED_DIR = DTF_DATA_DIR + "/included" 33 | DTF_GLOBAL_CONFIG = DTF_DATA_DIR + "/globals.ini" 34 | 35 | CONFIG_SECTION_BINDINGS = 'Bindings' 36 | CONFIG_SECTION_CLIENT = 'Client' 37 | CONFIG_SECTION_CONFIG = 'Config' 38 | 39 | 40 | class GlobalPropertyError(Exception): 41 | 42 | """General exception for global properties""" 43 | pass 44 | 45 | 46 | def get_binding(dtf_binding): 47 | 48 | """Read binding from global config""" 49 | 50 | return os.path.expanduser(get_generic_global(CONFIG_SECTION_BINDINGS, 51 | dtf_binding)) 52 | 53 | 54 | def get_all_bindings(): 55 | 56 | """Get all bindings""" 57 | 58 | return __get_section(CONFIG_SECTION_BINDINGS) 59 | 60 | 61 | def get_generic_global(section, prop): 62 | 63 | """Generic getter for getting a property""" 64 | 65 | if section is None: 66 | raise GlobalPropertyError("Section cannot be null!") 67 | elif prop is None: 68 | raise GlobalPropertyError("Property cannot be null!") 69 | 70 | global_conf = configparser.ConfigParser() 71 | global_conf.read(DTF_GLOBAL_CONFIG) 72 | 73 | try: 74 | return global_conf.get(section, prop) 75 | except configparser.NoSectionError: 76 | raise GlobalPropertyError("Section not found: %s" % section) 77 | except configparser.NoOptionError: 78 | raise GlobalPropertyError("Property not found: %s" % prop) 79 | 80 | 81 | def get_copy(): 82 | 83 | """Return a memory-resident copy""" 84 | 85 | global_conf = configparser.ConfigParser() 86 | global_conf.read(DTF_GLOBAL_CONFIG) 87 | 88 | return global_conf 89 | 90 | 91 | def __get_section(section): 92 | 93 | """Private helper to get all section values""" 94 | 95 | if section is None: 96 | raise GlobalPropertyError("Section cannot be null!") 97 | 98 | global_conf = configparser.ConfigParser() 99 | global_conf.read(DTF_GLOBAL_CONFIG) 100 | 101 | if not global_conf.has_section(section): 102 | raise GlobalPropertyError("Section not found: %s" % section) 103 | 104 | return global_conf.items(section) 105 | -------------------------------------------------------------------------------- /python-dtf/dtf/included.py: -------------------------------------------------------------------------------- 1 | # Android Device Testing Framework ("dtf") 2 | # Copyright 2013-2015 Jake Valletta (@jake_valletta) 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | """Python wrapper for Android tools""" 17 | 18 | from __future__ import absolute_import 19 | from subprocess import Popen, PIPE 20 | from dtf.globals import get_binding 21 | 22 | 23 | def aapt(cmd): 24 | 25 | """aapt wrapper""" 26 | 27 | aapt_path = get_binding("dtf_aapt") 28 | cmd = ("%s %s" % (aapt_path, cmd)).split(' ') 29 | 30 | proc = Popen(cmd, stdout=PIPE, stderr=PIPE, shell=False) 31 | 32 | stdout, stderr = proc.communicate() 33 | 34 | stdout = stdout.split("\n") 35 | stderr = stderr.split("\n") 36 | rtn = proc.returncode 37 | 38 | return stdout, stderr, rtn 39 | 40 | 41 | def apktool(cmd): 42 | 43 | """apktool wrapper""" 44 | 45 | apktool_path = get_binding("dtf_apktool") 46 | java_args = "java -Xmx512M -jar" 47 | 48 | cmd = ("%s %s %s" % (java_args, apktool_path, cmd)).split(' ') 49 | 50 | proc = Popen(cmd, stdout=PIPE, stderr=PIPE, shell=False) 51 | 52 | stdout, stderr = proc.communicate() 53 | 54 | stdout = stdout.split("\n") 55 | stderr = stderr.split("\n") 56 | rtn = proc.returncode 57 | 58 | return stdout, stderr, rtn 59 | 60 | 61 | def smali(cmd): 62 | 63 | """smali wrapper""" 64 | 65 | smali_path = get_binding("dtf_smali") 66 | java_args = "java -Xmx512M -jar" 67 | 68 | cmd = ("%s %s %s" % (java_args, smali_path, cmd)).split(' ') 69 | 70 | proc = Popen(cmd, stdout=PIPE, stderr=PIPE, shell=False) 71 | 72 | stdout, stderr = proc.communicate() 73 | 74 | stdout = stdout.split("\n") 75 | stderr = stderr.split("\n") 76 | rtn = proc.returncode 77 | 78 | return stdout, stderr, rtn 79 | 80 | 81 | def baksmali(cmd): 82 | 83 | """baksmali wrapper""" 84 | 85 | baksmali_path = get_binding("dtf_baksmali") 86 | java_args = "java -Xmx512M -jar" 87 | 88 | cmd = ("%s %s %s" % (java_args, baksmali_path, cmd)).split(' ') 89 | 90 | proc = Popen(cmd, stdout=PIPE, stderr=PIPE, shell=False) 91 | 92 | stdout, stderr = proc.communicate() 93 | 94 | stdout = stdout.split("\n") 95 | stderr = stderr.split("\n") 96 | rtn = proc.returncode 97 | 98 | return stdout, stderr, rtn 99 | 100 | 101 | def axmlprinter2(manifest_file_name, out_file_name): 102 | 103 | """axmlprinter2 wrapper""" 104 | 105 | axmlprinter2_path = get_binding("dtf_axmlprinter2") 106 | java_args = "java -Xmx256M -jar" 107 | 108 | cmd = ("%s %s %s" 109 | % (java_args, axmlprinter2_path, manifest_file_name)).split(' ') 110 | 111 | proc = Popen(cmd, stdout=PIPE, stderr=PIPE, shell=False) 112 | 113 | stdout = proc.communicate()[0] 114 | 115 | rtn = proc.returncode 116 | 117 | if len(stdout) == 0: 118 | return -1 119 | 120 | out_f = open(out_file_name, 'wb') 121 | 122 | try: 123 | out_f.write(stdout) 124 | finally: 125 | out_f.close() 126 | 127 | return rtn 128 | -------------------------------------------------------------------------------- /python-dtf/dtf/library.py: -------------------------------------------------------------------------------- 1 | # Android Device Testing Framework ("dtf") 2 | # Copyright 2013-2017 Jake Valletta (@jake_valletta) 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | """dtf Libraries Template""" 17 | 18 | from __future__ import absolute_import 19 | 20 | import os.path 21 | import sqlite3 22 | 23 | import dtf.core.utils as utils 24 | import dtf.properties as prop 25 | 26 | TAG = "dtf-library" 27 | 28 | 29 | class DtfDbException(Exception): # pylint: disable=too-few-public-methods 30 | 31 | """Base class for DB Exceptions""" 32 | 33 | def __init__(self, message): 34 | 35 | """Raise new exception""" 36 | 37 | # Call the base class constructor with the parameters it needs 38 | Exception.__init__(self, message) 39 | 40 | 41 | class DbLibrary(object): 42 | 43 | """ 44 | Base class for creating a python database library with dtf. 45 | """ 46 | 47 | # This needs to be set 48 | db_name = "" 49 | 50 | db_path = "" 51 | db_connection = None 52 | 53 | def __init__(self, safe=False, project_dir=None): 54 | 55 | """Initialize new instance""" 56 | 57 | if project_dir is None: 58 | db_path = "%s/%s/%s" % (prop.TOP, utils.DBS_DIRECTORY, 59 | self.db_name) 60 | else: 61 | db_path = "%s/%s/%s" % (project_dir, utils.DBS_DIRECTORY, 62 | self.db_name) 63 | 64 | if safe and not os.path.isfile(db_path): 65 | raise DtfDbException("Database file not found : %s!" % db_path) 66 | 67 | self.db_path = db_path 68 | self.db_connection = sqlite3.connect(db_path) 69 | 70 | # Call post init for anyone needing additional stuff here 71 | self.post_init() 72 | 73 | def post_init(self): 74 | 75 | """Post-init to allow additional processing after __init__""" 76 | pass 77 | 78 | # The following are not meant to be overridden. 79 | def commit(self): 80 | 81 | """Commit DB changes""" 82 | 83 | if self.db_connection is None: 84 | raise DtfDbException("No active DB connection!") 85 | 86 | return self.db_connection.commit() 87 | 88 | def get_cursor(self): 89 | 90 | """Obtain handle to cursor""" 91 | 92 | if self.db_connection is None: 93 | raise DtfDbException("No active DB connection!") 94 | 95 | return self.db_connection.cursor() 96 | 97 | def close(self): 98 | 99 | """Close handle to DB""" 100 | 101 | if self.db_connection is None: 102 | raise DtfDbException("No Active DB connection!") 103 | 104 | self.db_connection.close() 105 | 106 | return 107 | 108 | @classmethod 109 | def exists(cls): 110 | 111 | """Simple check to determine if DB exists""" 112 | 113 | db_path = "%s/%s/%s" % (prop.TOP, utils.DBS_DIRECTORY, 114 | cls.db_name) 115 | 116 | return bool(os.path.isfile(db_path)) 117 | -------------------------------------------------------------------------------- /python-dtf/dtf/logging.py: -------------------------------------------------------------------------------- 1 | # Android Device Testing Framework ("dtf") 2 | # Copyright 2013-2015 Jake Valletta (@jake_valletta) 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | """dtf logging framework""" 17 | 18 | from __future__ import absolute_import 19 | from sys import stdout 20 | from time import localtime, strftime 21 | 22 | from colored import attr 23 | 24 | import dtf.core.utils as utils 25 | import dtf.colors as colors 26 | 27 | 28 | # Can override just like the shell 29 | LOG_LEVEL_FILE = 4 # By default, log E-V 30 | LOG_LEVEL_STDOUT = 4 # By default, log E-V 31 | 32 | # Internals ########################################################### 33 | LOG_FILE = None 34 | 35 | # Open file on module import 36 | TOP = utils.get_project_root() 37 | if TOP is not None: 38 | LOG_FILE = open("%s/%s" % (TOP, utils.LOG_FILE_NAME), 'a') 39 | 40 | 41 | def __get_date(): 42 | 43 | """Format current date""" 44 | 45 | return strftime("%a %b %d %H:%M:%S %Z %Y", localtime()) 46 | 47 | 48 | def __log(buf, entry): 49 | 50 | """Low level print function""" 51 | 52 | buf.write(entry) 53 | 54 | 55 | # Low level stdout print 56 | def __log_to_stdout(color, date, tag, message): 57 | 58 | """Write entry to stdout""" 59 | 60 | entry = "%s[%s] %s - %s %s\n" % (color, date, tag, message, attr(0)) 61 | __log(stdout, entry) 62 | 63 | 64 | # Low level file print 65 | def __log_to_file(date, tag, message): 66 | 67 | """Write entry to stderr""" 68 | 69 | if LOG_FILE is None: 70 | return 71 | 72 | entry = "[%s] %s - %s\n" % (date, tag, message) 73 | __log(LOG_FILE, entry) 74 | 75 | # ###################################################################### 76 | 77 | 78 | # Public Calls ######################################################### 79 | def e(tag, message): # pylint: disable=invalid-name 80 | 81 | """Print an error message""" 82 | 83 | date = __get_date() 84 | if LOG_LEVEL_STDOUT >= 1: 85 | __log_to_stdout(colors.COLOR_ERR, date, tag+"/E", message) 86 | if LOG_LEVEL_FILE >= 1: 87 | __log_to_file(date, tag+"/E", message) 88 | 89 | 90 | def w(tag, message): # pylint: disable=invalid-name 91 | 92 | """Print a warning message""" 93 | 94 | date = __get_date() 95 | if LOG_LEVEL_STDOUT >= 2: 96 | __log_to_stdout(colors.COLOR_WARN, date, tag+"/W", message) 97 | if LOG_LEVEL_FILE >= 2: 98 | __log_to_file(date, tag+"/W", message) 99 | 100 | 101 | def i(tag, message): # pylint: disable=invalid-name 102 | 103 | """Print an informational message (non-debug)""" 104 | 105 | date = __get_date() 106 | if LOG_LEVEL_STDOUT >= 3: 107 | __log_to_stdout(colors.COLOR_INFO, date, tag+"/I", message) 108 | if LOG_LEVEL_FILE >= 3: 109 | __log_to_file(date, tag+"/I", message) 110 | 111 | 112 | def v(tag, message): # pylint: disable=invalid-name 113 | 114 | """Print a verbose message (non-debug)""" 115 | 116 | date = __get_date() 117 | if LOG_LEVEL_STDOUT >= 4: 118 | __log_to_stdout(colors.COLOR_VERB, date, tag+"/V", message) 119 | if LOG_LEVEL_FILE >= 4: 120 | __log_to_file(date, tag+"/V", message) 121 | 122 | 123 | def d(tag, message): # pylint: disable=invalid-name 124 | 125 | """Print a debugging message""" 126 | 127 | date = __get_date() 128 | if LOG_LEVEL_STDOUT >= 5: 129 | __log_to_stdout(colors.COLOR_DEB, date, tag+"/D", message) 130 | if LOG_LEVEL_FILE >= 5: 131 | __log_to_file(date, tag+"/D", message) 132 | 133 | 134 | # Multi-line Logging 135 | def e_ml(tag, messages): 136 | 137 | """Print a multi-line error message""" 138 | 139 | if not isinstance(messages, list): 140 | raise TypeError 141 | 142 | for message in messages: 143 | if message == "": 144 | continue 145 | 146 | e(tag, message) 147 | 148 | 149 | def w_ml(tag, messages): 150 | 151 | """Print a multi-lne warning message""" 152 | 153 | if not isinstance(messages, list): 154 | raise TypeError 155 | 156 | for message in messages: 157 | if message == "": 158 | continue 159 | 160 | w(tag, message) 161 | 162 | 163 | def i_ml(tag, messages): 164 | 165 | """Print a multi-line informational message""" 166 | 167 | if not isinstance(messages, list): 168 | raise TypeError 169 | 170 | for message in messages: 171 | if message == "": 172 | continue 173 | 174 | i(tag, message) 175 | 176 | 177 | def v_ml(tag, messages): 178 | 179 | """Print a multi-line verbose message""" 180 | 181 | if not isinstance(messages, list): 182 | raise TypeError 183 | 184 | for message in messages: 185 | if message == "": 186 | continue 187 | 188 | v(tag, message) 189 | 190 | 191 | def d_ml(tag, messages): 192 | 193 | """Print a multi-line debugging message""" 194 | 195 | if not isinstance(messages, list): 196 | raise TypeError 197 | 198 | for message in messages: 199 | if message == "": 200 | continue 201 | 202 | d(tag, message) 203 | ######################################################################### 204 | -------------------------------------------------------------------------------- /python-dtf/dtf/module.py: -------------------------------------------------------------------------------- 1 | # Android Device Testing Framework ("dtf") 2 | # Copyright 2013-2015 Jake Valletta (@jake_valletta) 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | """dtf Module Template""" 17 | 18 | from __future__ import absolute_import 19 | import os 20 | 21 | import dtf.logging as log 22 | import dtf.properties as prop 23 | import dtf.core.packagemanager as pm 24 | from dtf.globals import DTF_PACKAGES_DIR 25 | from dtf.exceptions import DtfException 26 | 27 | TAG = "dtf-module" 28 | 29 | 30 | def sub_cmd(name, usage=""): 31 | 32 | """Decorator for routing a sub command""" 33 | 34 | def decorator(func): 35 | 36 | """Save name of the sub command + function""" 37 | 38 | func.sub_cmd_name = name 39 | func.sub_cmd_route = func.__name__ 40 | func.sub_cmd_usage = usage 41 | 42 | return func 43 | 44 | return decorator 45 | 46 | 47 | class Module(object): 48 | 49 | """ 50 | Base class for creating a python module with dtf. Override the 51 | fields below, and implement an execute(self, args) method. 52 | """ 53 | 54 | name = "MyModule" 55 | version = "1.0.0" 56 | license = "N/A" 57 | author = "N/A" 58 | about = "A basic dtf module." 59 | 60 | requires = [] 61 | min_sdk = 0 62 | 63 | launch_dir = "" 64 | 65 | __self__ = '' 66 | 67 | def run(self, args): 68 | 69 | """ 70 | Internal entry point for starting a module. It basically executes 71 | the 'execute' method if it exists. 72 | """ 73 | 74 | # Save module name 75 | self.__self__ = type(self).__name__ 76 | 77 | # Determine if we have an execute() method. 78 | if hasattr(self, 'execute'): 79 | 80 | # Do python logging override 81 | try: 82 | log.LOG_LEVEL_STDOUT = int(os.environ['GLOG_LEVEL']) 83 | except KeyError: 84 | pass 85 | except ValueError: 86 | log.w(TAG, "Invalid GLOG_LEVEL value (0-5 is allowed)") 87 | 88 | result = getattr(self, 'execute')(args) 89 | 90 | else: 91 | 92 | log.e(TAG, "Module '%s' does not define a entry point!" 93 | % self.__self__) 94 | result = None 95 | 96 | return result 97 | 98 | @classmethod 99 | def get_diff_dir(cls): 100 | 101 | """Determine which diffing db to use""" 102 | 103 | # First check for a property override. 104 | if prop.test_prop('Local', 'diff-data-dir'): 105 | diff_dir = prop.get_prop('Local', 'diff-data-dir') 106 | 107 | if not os.path.isdir(diff_dir): 108 | raise DtfException("Unable to find diffing directory!") 109 | else: 110 | return diff_dir 111 | 112 | # Not set 113 | else: 114 | sdk = prop.get_prop("Info", "sdk") 115 | if pm.is_package_installed("aosp-data-%s" % sdk): 116 | 117 | diff_dir = ("%s/aosp-data-%s" 118 | % (DTF_PACKAGES_DIR, sdk)) 119 | 120 | return diff_dir 121 | else: 122 | raise DtfException("AOSP data not installed for this API!") 123 | 124 | def cd_launch_dir(self): 125 | 126 | """Change to the launch directory""" 127 | 128 | os.chdir(self.launch_dir) 129 | -------------------------------------------------------------------------------- /python-dtf/dtf/properties.py: -------------------------------------------------------------------------------- 1 | # Android Device Testing Framework ("dtf") 2 | # Copyright 2013-2015 Jake Valletta (@jake_valletta) 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | """dtf property support""" 17 | 18 | from __future__ import absolute_import 19 | from os.path import abspath, join, isfile 20 | from os import getcwd, pardir 21 | 22 | import configparser 23 | 24 | import dtf.core.utils as utils 25 | import dtf.logging as log 26 | 27 | CONFIG_FILE_NAME = utils.CONFIG_FILE_NAME 28 | 29 | TAG = "dtf-properties" 30 | 31 | 32 | class PropertyError(Exception): 33 | 34 | """General exception for properties""" 35 | pass 36 | 37 | 38 | def __upsearch(file_name, dir_name): 39 | 40 | """Search upward for file""" 41 | 42 | if isfile("%s/%s" % (dir_name, file_name)): 43 | return dir_name 44 | else: 45 | new_dir = abspath(join(dir_name, pardir)) 46 | if dir_name == new_dir: 47 | return None 48 | return __upsearch(file_name, new_dir) 49 | 50 | 51 | TOP = __upsearch(CONFIG_FILE_NAME, getcwd()) 52 | 53 | 54 | def __load_config(): 55 | 56 | """Load the current project configuration""" 57 | 58 | config = configparser.ConfigParser() 59 | config.read(CONFIG_FILE_NAME) 60 | 61 | return config 62 | 63 | 64 | def __update_config(config): 65 | 66 | """Update config file""" 67 | 68 | prop_f = open(CONFIG_FILE_NAME, 'w') 69 | config.write(prop_f) 70 | prop_f.close() 71 | 72 | 73 | def get_prop(section, prop): 74 | 75 | """Get a property value""" 76 | 77 | config = __load_config() 78 | section = section.capitalize() 79 | 80 | # Caller needs to check return if he/she cares what the issue was. 81 | try: 82 | rtn = config.get(section, prop) 83 | except configparser.NoSectionError: 84 | err = "Property section not found: %s" % section 85 | raise PropertyError(err) 86 | except configparser.NoOptionError: 87 | err = r"Property not found: %s\%s" % (section, prop) 88 | raise PropertyError(err) 89 | 90 | return rtn 91 | 92 | 93 | def set_prop(section, prop, value): 94 | 95 | """Set a property""" 96 | 97 | config = __load_config() 98 | section = section.capitalize() 99 | 100 | # Add section if it doesnt exist 101 | if not config.has_section(section): 102 | config.add_section(section) 103 | 104 | # Set the new parameter 105 | config.set(section, prop, value) 106 | 107 | __update_config(config) 108 | 109 | return 0 110 | 111 | 112 | def del_prop(section, prop): 113 | 114 | """Delete a property""" 115 | 116 | config = __load_config() 117 | section = section.capitalize() 118 | 119 | rtn = None 120 | 121 | # Remove the parameter 122 | try: 123 | rtn = config.remove_option(section, prop) 124 | except configparser.NoSectionError: 125 | log.w(TAG, "Property not removed (the section did not exist).") 126 | return -1 127 | 128 | if not rtn: 129 | log.w(TAG, "Property not removed (did not exist).") 130 | return -2 131 | 132 | # Let's make sure we don't have an empty section now. 133 | if len(config.items(section)) == 0: 134 | config.remove_section(section) 135 | 136 | __update_config(config) 137 | 138 | return 0 139 | 140 | 141 | def test_prop(section, prop): 142 | 143 | """Test if a property is set or not""" 144 | 145 | config = __load_config() 146 | section = section.capitalize() 147 | rtn = 0 148 | 149 | try: 150 | config.get(section, prop) 151 | rtn = 1 152 | except configparser.NoSectionError: 153 | rtn = 0 154 | except configparser.NoOptionError: 155 | rtn = 0 156 | 157 | return rtn 158 | -------------------------------------------------------------------------------- /python-dtf/generate_coverage.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Android Device Testing Framework ("dtf") 3 | # Copyright 2013-2016 Jake Valletta (@jake_valletta) 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # 17 | # Generate coverage information 18 | 19 | # If we are in travis, we don't need to use virtualenv. For now, 20 | # locally we need to activate it. 21 | if [ "$TRAVIS" != "true" ]; then 22 | echo "Activating virtualenv" 23 | . venv/bin/activate 24 | fi 25 | 26 | export COVERAGE_PROCESS_START=.coveragerc 27 | 28 | # Remove old coverage data 29 | coverage erase 30 | 31 | # Just incase, remove any .dtf* stuff. 32 | rm .dtfini .dtflog 2>/dev/null 33 | 34 | # Make sure dtf is installed. 35 | python setup.py develop 36 | 37 | # We need to make sure there is no .dtf, but for local testing, 38 | # I'd rather not have my stuff blown away. Move it, then move back. 39 | if [ -e ~/.dtf ]; then 40 | mv ~/.dtf ~/.dtf_bk 41 | fi 42 | 43 | # ============ Unit Tests ============== 44 | # Mock a ~/.dtf directory for unit tests. 45 | mkdir -p ~/.dtf/binaries/ ~/.dtf/included/ ~/.dtf/libraries/ ~/.dtf/modules/ ~/.dtf/packages/ 46 | tar -xC ~/.dtf/included -f dtf/included.tar 47 | 48 | coverage run -m py.test tests/unit 49 | 50 | # Reset the mocked ~/.dtf/ 51 | rm -rf ~/.dtf 52 | 53 | # ========= Integration Tests ========== 54 | # First run non-device integration. 55 | coverage run -m py.test tests/integration 56 | 57 | # These tests will require an active emulator/device 58 | # Only run these if we are Travis OR manually request. 59 | if [ "$TRAVIS" = "true" -o "$DO_DEVICE_INTEGRATION" = "1" ]; then 60 | adb install $(ls included/dtfClient/*.apk) 61 | adb shell am startservice -a com.dtf.action.name.INITIALIZE 62 | coverage run -m py.test tests/integration-device 63 | fi 64 | 65 | # Move it back 66 | if [ -e ~/.dtf_bk ]; then 67 | rm -rf ~/.dtf 68 | mv ~/.dtf_bk ~/.dtf 69 | fi 70 | 71 | # Combine and show 72 | coverage combine 73 | 74 | coverage report 75 | coverage html 76 | 77 | python setup.py develop --uninstall 78 | 79 | if [ "$TRAVIS" != "true" ]; then 80 | deactivate 81 | fi 82 | -------------------------------------------------------------------------------- /python-dtf/setup.cfg: -------------------------------------------------------------------------------- 1 | [install_lib] 2 | compile=0 3 | -------------------------------------------------------------------------------- /python-dtf/setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Android Device Testing Framework ("dtf") 3 | # Copyright 2013-2015 Jake Valletta (@jake_valletta) 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # 17 | """dtf Setup Script""" 18 | 19 | from __future__ import absolute_import 20 | from setuptools import setup 21 | import os 22 | import sys 23 | 24 | # Read in the version data. 25 | def generate_version_string(): 26 | 27 | """Generate version string based on VERSION""" 28 | 29 | values = open(os.path.join( 30 | os.path.dirname(__file__), 31 | "dtf/VERSION")).read().rstrip().split('-') 32 | 33 | if len(values) < 3: 34 | return "%s.%s" % (values[0], values[1]) 35 | else: 36 | return "%s.%s.%s" % (values[0], values[1], values[2]) 37 | 38 | requires = ['colored', 39 | 'configparser', 40 | 'lxml', 41 | 'semantic_version', 42 | 'requests'] 43 | 44 | if sys.version_info[:2] == (2, 6): 45 | requires.append("configparser") 46 | 47 | setup( 48 | name='dtf', 49 | version=generate_version_string(), 50 | description='Android Device Testing Framework (dtf)', 51 | long_description=open( 52 | os.path.join(os.path.dirname(__file__), "README.rst")).read(), 53 | 54 | url='https://thecobraden.com/projects/dtf', 55 | download_url='https://github.com/jakev/dtf', 56 | 57 | author='Jake Valletta', 58 | author_email='javallet@gmail.com', 59 | license='ASL', 60 | 61 | classifiers=[ 62 | 'Development Status :: 4 - Beta', 63 | 'Intended Audience :: Information Technology', 64 | 'Topic :: Security', 65 | 'License :: OSI Approved :: Apache Software License', 66 | 'Operating System :: POSIX :: Linux', 67 | 'Programming Language :: Python :: 2', 68 | 'Programming Language :: Python :: 2.7', 69 | 'Programming Language :: Python :: 3', 70 | 'Programming Language :: Python :: 3.3'], 71 | 72 | keywords='android device security mobile reverse-engineering framework', 73 | 74 | packages=["dtf", 75 | "dtf.core", 76 | "dtf.core.cmds"], 77 | 78 | install_requires=requires, 79 | setup_requires=['pytest-runner'], 80 | 81 | entry_points={ 82 | 'console_scripts': [ 83 | 'dtf = dtf.launcher:main', 84 | 'dtf_check = dtf.checker:main', 85 | ], 86 | }, 87 | 88 | zip_safe=False, 89 | include_package_data=True, 90 | ) 91 | -------------------------------------------------------------------------------- /python-dtf/tests/data-files/hello-world.apk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/android-dtf/dtf/a761ace77cea051bfb88d56df65ae6b83f664480/python-dtf/tests/data-files/hello-world.apk -------------------------------------------------------------------------------- /python-dtf/tests/data-files/integration_client_upload_data: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/android-dtf/dtf/a761ace77cea051bfb88d56df65ae6b83f664480/python-dtf/tests/data-files/integration_client_upload_data -------------------------------------------------------------------------------- /python-dtf/tests/data-files/integration_module_invalid_noclass: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import dtf.logging as log 4 | 5 | from dtf.module import Module 6 | 7 | TAG = "TestModule" 8 | 9 | 10 | class test_nope(Module): 11 | 12 | """A Module class""" 13 | 14 | about = 'Integration test' 15 | author = 'Jake Valletta (jakev)' 16 | name = 'test_nope' 17 | version = '1.0.0' 18 | 19 | def execute(self, args): 20 | 21 | """Main class executor""" 22 | 23 | log.i(TAG, "I was launched!") 24 | 25 | return 0 26 | -------------------------------------------------------------------------------- /python-dtf/tests/data-files/integration_module_invalid_noexecargs: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import dtf.logging as log 4 | 5 | from dtf.module import Module 6 | 7 | TAG = "TestModule" 8 | 9 | 10 | class test_noexecargs(Module): 11 | 12 | """A Module class""" 13 | 14 | about = 'Integration test' 15 | author = 'Jake Valletta (jakev)' 16 | name = 'test_noexecargs' 17 | version = '1.0.0' 18 | -------------------------------------------------------------------------------- /python-dtf/tests/data-files/integration_module_valid_kraise: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import dtf.logging as log 4 | import dtf.module as module 5 | 6 | TAG = "TestModule" 7 | 8 | 9 | class test_kraise(module.Module): 10 | 11 | """A Module class""" 12 | 13 | about = 'Integration test' 14 | author = 'Jake Valletta (jakev)' 15 | name = 'test_kraise' 16 | version = '1.0.0' 17 | 18 | @module.sub_cmd("test") 19 | def cmd_test(self, args): 20 | 21 | raise KeyboardInterrupt("On no!") 22 | -------------------------------------------------------------------------------- /python-dtf/tests/data-files/integration_module_valid_mod: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import dtf.logging as log 4 | 5 | from dtf.module import Module 6 | 7 | TAG = "TestModule" 8 | 9 | 10 | class test_execute(Module): 11 | 12 | """A Module class""" 13 | 14 | about = 'Integration test' 15 | author = 'Jake Valletta (jakev)' 16 | name = 'test_execute' 17 | version = '1.0.0' 18 | 19 | def execute(self, args): 20 | 21 | """Main class executor""" 22 | 23 | log.i(TAG, "I was launched!") 24 | 25 | return 0 26 | -------------------------------------------------------------------------------- /python-dtf/tests/data-files/integration_module_valid_raise: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import dtf.logging as log 4 | import dtf.module as module 5 | 6 | TAG = "TestModule" 7 | 8 | 9 | class test_raise(module.Module): 10 | 11 | """A Module class""" 12 | 13 | about = 'Integration test' 14 | author = 'Jake Valletta (jakev)' 15 | name = 'test_raise' 16 | version = '1.0.0' 17 | 18 | @module.sub_cmd("test") 19 | def cmd_test(self, args): 20 | 21 | raise IOError("On no!") 22 | -------------------------------------------------------------------------------- /python-dtf/tests/data-files/integration_module_valid_subs: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import dtf.logging as log 4 | import dtf.module as module 5 | 6 | TAG = "TestModule" 7 | 8 | 9 | class test_sub(module.Module): 10 | 11 | """Module class for viewing binary information""" 12 | 13 | about = 'Integration test - valid module' 14 | author = 'Jake Valletta (jakev)' 15 | name = 'test_module' 16 | version = '1.0.0' 17 | 18 | @module.sub_cmd("test") 19 | def cmd_test(self, args): 20 | 21 | log.i(TAG, "test called!") 22 | -------------------------------------------------------------------------------- /python-dtf/tests/data-files/integration_pm_binary_install: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/android-dtf/dtf/a761ace77cea051bfb88d56df65ae6b83f664480/python-dtf/tests/data-files/integration_pm_binary_install -------------------------------------------------------------------------------- /python-dtf/tests/data-files/integration_pm_install_library.dz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/android-dtf/dtf/a761ace77cea051bfb88d56df65ae6b83f664480/python-dtf/tests/data-files/integration_pm_install_library.dz -------------------------------------------------------------------------------- /python-dtf/tests/data-files/integration_pm_install_package.dz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/android-dtf/dtf/a761ace77cea051bfb88d56df65ae6b83f664480/python-dtf/tests/data-files/integration_pm_install_package.dz -------------------------------------------------------------------------------- /python-dtf/tests/data-files/integration_pm_module_install_bash: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # DTF Core Content 3 | # Copyright 2013-2015 Jake Valletta (@jake_valletta) 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | #@About: Get an APK (optionally with DEX) from device. 18 | #@Author: Jake Valletta (jakev) 19 | #@Version: 1.1.0 20 | 21 | . $DTF_CORE 22 | . $DTF_LOG 23 | 24 | usage() 25 | { 26 | echo "Usage apkget OPTIONS " 27 | echo " OPTIONS:" 28 | echo " -o Pull package's ODEX" 29 | echo " -s Search for package" 30 | echo " -p Pull package" 31 | echo " -h Prints this menu" 32 | exit 1 33 | } 34 | 35 | if [ $# -lt 1 ] ; then 36 | usage 37 | fi 38 | 39 | package="" 40 | search="" 41 | odex="" 42 | 43 | #Process the arguments 44 | while getopts hdeo:p:s: opt 45 | do 46 | case "$opt" in 47 | h) usage;; 48 | o) odex=$OPTARG;; 49 | p) package=$OPTARG;; 50 | s) search=$OPTARG;; 51 | \?) usage;; 52 | esac 53 | done 54 | 55 | adb wait-for-device 56 | 57 | cd "${LAUNCH_DIR}" 58 | 59 | if [ $search ]; then 60 | echo "Searching for \"${search}\"..." 61 | adb shell "pm list packages"|grep -i "$search"|awk '{print $1}' 62 | exit 0 63 | 64 | elif [ $package ]; then 65 | log_i "Attempting to pull APK for \"${package}\"..." 66 | package_path=$(adb shell pm path ${package} | tr -d '\r' |awk -F":" '{print $2}') 67 | 68 | if [ -z $package_path ]; then 69 | log_e "No packages match the string \"${package}\"" 70 | exit 1 71 | else 72 | log_i "Found match for \"${package}\"" 73 | adb pull $package_path > /dev/null 2>&1 74 | exit 0 75 | fi 76 | 77 | elif [ $odex ]; then 78 | 79 | log_i "Attempting to pull ODEX for \"${odex}\"..." 80 | apk_path=$(adb shell pm path ${odex} | tr -d '\r' |awk -F":" '{print $2}') 81 | 82 | if [ $apk_path ]; then 83 | log_i "Found match for \"${odex}\"" 84 | 85 | package_path=$(dirname $apk_path) 86 | odex_name=$(basename $apk_path| sed 's/\.apk$/.odex/') 87 | 88 | # Need to act differently depending on Dalvik/ART 89 | vm_type=$(dtf prop get Info vmtype) 90 | 91 | # Device is using ART/ART64 92 | if [[ "$vm_type" == "ART"* ]]; then 93 | 94 | # It's not with checking the bits, as both can exist. 95 | log_i "Attempting to pull 32-bit ODEX..." 96 | adb pull ${package_path}/arm/${odex_name} > /dev/null 2>&1 97 | 98 | log_i "Attempting to pull 64-bit ODEX..." 99 | adb pull ${package_path}/arm64/${odex_name} > /dev/null 2>&1 100 | 101 | # Dalvik, so path is easy. 102 | else 103 | package_path=$(dirname $apk_path) 104 | odex_name=$(basename $apk_path| sed 's/\.apk$/.odex/') 105 | log_i "Attempting to pull 32-bit ODEX..." 106 | adb pull ${package_path}/${odex_name} > /dev/null 2>&1 107 | fi 108 | else 109 | log_e "No packages match the string \"${odex}\"" 110 | exit 1 111 | fi 112 | else 113 | echo "[ERROR] You must specify -p or -s!" 114 | usage 115 | fi 116 | -------------------------------------------------------------------------------- /python-dtf/tests/data-files/integration_pm_valid_zip.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/android-dtf/dtf/a761ace77cea051bfb88d56df65ae6b83f664480/python-dtf/tests/data-files/integration_pm_valid_zip.zip -------------------------------------------------------------------------------- /python-dtf/tests/data-files/nexus_5x: -------------------------------------------------------------------------------- 1 | [Info] 2 | serial = 1234567890123456 3 | kernel = Linux version 3.10.73-g8eaa82a (android-build@vpba27.mtv.corp.google.com) (gcc version 4.9.x-google 20140827 (prerelease) (GCC) ) #1 SMP PREEMPT Sat Mar 26 01:36:22 UTC 2016 4 | sdk = 23 5 | path = /sbin:/vendor/bin:/system/sbin:/system/bin:/system/xbin 6 | bootclasspath-jars = /system/framework/core-libart.jar:/system/framework/conscrypt.jar:/system/framework/okhttp.jar:/system/framework/core-junit.jar:/system/framework/bouncycastle.jar:/system/framework/ext.jar:/system/framework/framework.jar:/system/framework/telephony-common.jar:/system/framework/voip-common.jar:/system/framework/ims-common.jar:/system/framework/apache-xml.jar:/system/framework/org.apache.http.legacy.boot.jar 7 | version-string = google-bullhead_MTC19T 8 | cpu-bits = 64 9 | vmtype = ART 10 | seandroid-state = Enforcing 11 | busybox = /data/data/com.dtf.client/files/busybox 12 | -------------------------------------------------------------------------------- /python-dtf/tests/data-files/valid_android_manifest.xml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/android-dtf/dtf/a761ace77cea051bfb88d56df65ae6b83f664480/python-dtf/tests/data-files/valid_android_manifest.xml -------------------------------------------------------------------------------- /python-dtf/tests/integration-device/client/test_client.py: -------------------------------------------------------------------------------- 1 | # Android Device Testing Framework ("dtf") 2 | # Copyright 2013-2016 Jake Valletta (@jake_valletta) 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | """Integration tests for the "client" utility""" 17 | 18 | from __future__ import absolute_import 19 | import dtf.testutils as testutils 20 | 21 | 22 | class ClientTests(testutils.BasicIntegrationDeviceTest): 23 | 24 | """Wraper for integration tests""" 25 | 26 | def test_no_args(self): 27 | 28 | """Run with not args""" 29 | 30 | rtn = self.run_cmd("client") 31 | 32 | assert(rtn.return_code == 0) 33 | 34 | 35 | def test_not_subcommand(self): 36 | 37 | """Try to call invalid sub command""" 38 | 39 | rtn = self.run_cmd("client NOT_EXIST") 40 | 41 | assert(rtn.return_code == 0) 42 | -------------------------------------------------------------------------------- /python-dtf/tests/integration-device/client/test_client_download.py: -------------------------------------------------------------------------------- 1 | # Android Device Testing Framework ("dtf") 2 | # Copyright 2013-2016 Jake Valletta (@jake_valletta) 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | """Integration tests for the "client download" utility""" 17 | 18 | from __future__ import absolute_import 19 | import dtf.testutils as testutils 20 | import dtf.core.utils as utils 21 | 22 | class ClientDownloadTests(testutils.BasicIntegrationDeviceTest): 23 | 24 | """Wraper for integration tests""" 25 | 26 | def test_download(self): 27 | 28 | """Do an download""" 29 | 30 | rtn = self.run_cmd("client download /system/etc/hosts") 31 | 32 | utils.delete_file("hosts") 33 | 34 | assert(rtn.return_code == 0) 35 | 36 | def test_download_local_exists(self): 37 | 38 | """Try to download a file that already exists""" 39 | 40 | utils.touch("hosts") 41 | rtn = self.run_cmd("client download /system/etc/hosts") 42 | 43 | utils.delete_file("hosts") 44 | 45 | assert(rtn.return_code == 255) 46 | 47 | def test_download_path(self): 48 | 49 | """Do a download to a path""" 50 | 51 | rtn = self.run_cmd("client download --path ./hosts /system/etc/hosts") 52 | 53 | utils.delete_file("hosts") 54 | 55 | assert(rtn.return_code == 0) 56 | 57 | def test_download_not_installed(self): 58 | 59 | """Attempt to download with non-existent APK""" 60 | 61 | rtn = self.run_cmd("client remove") 62 | assert(rtn.return_code == 0) 63 | 64 | rtn = self.run_cmd("client download /system/etc/hosts") 65 | assert(rtn.return_code == 255) 66 | 67 | rtn = self.run_cmd("client install") 68 | assert(rtn.return_code == 0) 69 | -------------------------------------------------------------------------------- /python-dtf/tests/integration-device/client/test_client_execute.py: -------------------------------------------------------------------------------- 1 | # Android Device Testing Framework ("dtf") 2 | # Copyright 2013-2016 Jake Valletta (@jake_valletta) 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | """Integration tests for the "client execute" utility""" 17 | 18 | from __future__ import absolute_import 19 | import dtf.testutils as testutils 20 | 21 | 22 | class ClientExecuteTests(testutils.BasicIntegrationDeviceTest): 23 | 24 | """Wraper for integration tests""" 25 | 26 | def test_no_args(self): 27 | 28 | """Run execute with no args""" 29 | 30 | rtn = self.run_cmd("client execute") 31 | assert(rtn.return_code == 255) 32 | 33 | def test_run_ls(self): 34 | 35 | """Run ls command""" 36 | 37 | rtn = self.run_cmd("client execute ls") 38 | assert(rtn.return_code == 0) 39 | 40 | def test_not_installed(self): 41 | 42 | """Test but not installed""" 43 | 44 | rtn = self.run_cmd("client remove") 45 | assert(rtn.return_code == 0) 46 | 47 | rtn = self.run_cmd("client execute ls") 48 | assert(rtn.return_code == 255) 49 | 50 | rtn = self.run_cmd("client install") 51 | assert(rtn.return_code == 0) 52 | -------------------------------------------------------------------------------- /python-dtf/tests/integration-device/client/test_client_install.py: -------------------------------------------------------------------------------- 1 | # Android Device Testing Framework ("dtf") 2 | # Copyright 2013-2016 Jake Valletta (@jake_valletta) 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | """Integration tests for the "client install" utility""" 17 | 18 | from __future__ import absolute_import 19 | import dtf.testutils as testutils 20 | 21 | 22 | class ClientInstallTests(testutils.BasicIntegrationDeviceTest): 23 | 24 | """Wraper for integration tests""" 25 | 26 | def test_install(self): 27 | 28 | """Do an install""" 29 | 30 | rtn = self.run_cmd("client install") 31 | assert(rtn.return_code == 0) 32 | -------------------------------------------------------------------------------- /python-dtf/tests/integration-device/client/test_client_remove.py: -------------------------------------------------------------------------------- 1 | # Android Device Testing Framework ("dtf") 2 | # Copyright 2013-2016 Jake Valletta (@jake_valletta) 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | """Integration tests for the "client remove" utility""" 17 | 18 | from __future__ import absolute_import 19 | import dtf.testutils as testutils 20 | 21 | 22 | class ClientRemoveTests(testutils.BasicIntegrationDeviceTest): 23 | 24 | """Wraper for integration tests""" 25 | 26 | def test_uninstall(self): 27 | 28 | """Run ls command""" 29 | 30 | rtn = self.run_cmd("client remove") 31 | assert(rtn.return_code == 0) 32 | 33 | rtn = self.run_cmd("client install") 34 | assert(rtn.return_code == 0) 35 | -------------------------------------------------------------------------------- /python-dtf/tests/integration-device/client/test_client_restart.py: -------------------------------------------------------------------------------- 1 | # Android Device Testing Framework ("dtf") 2 | # Copyright 2013-2016 Jake Valletta (@jake_valletta) 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | """Integration tests for the "client restart" utility""" 17 | 18 | from __future__ import absolute_import 19 | import dtf.testutils as testutils 20 | 21 | 22 | class ClientRestartTests(testutils.BasicIntegrationDeviceTest): 23 | 24 | """Wraper for integration tests""" 25 | 26 | def test_restart(self): 27 | 28 | """Test if is installed""" 29 | 30 | rtn = self.run_cmd("client restart") 31 | assert(rtn.return_code == 0) 32 | -------------------------------------------------------------------------------- /python-dtf/tests/integration-device/client/test_client_status.py: -------------------------------------------------------------------------------- 1 | # Android Device Testing Framework ("dtf") 2 | # Copyright 2013-2016 Jake Valletta (@jake_valletta) 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | """Integration tests for the "client status" utility""" 17 | 18 | from __future__ import absolute_import 19 | import dtf.testutils as testutils 20 | 21 | 22 | class ClientStatusTests(testutils.BasicIntegrationDeviceTest): 23 | 24 | """Wraper for integration tests""" 25 | 26 | def test_status_installed(self): 27 | 28 | """Test if is installed""" 29 | 30 | rtn = self.run_cmd("client status") 31 | assert(rtn.return_code == 0) 32 | 33 | def test_status_not_installed(self): 34 | 35 | """"Test if not installed""" 36 | 37 | rtn = self.run_cmd("client remove") 38 | assert(rtn.return_code == 0) 39 | 40 | rtn = self.run_cmd("client status") 41 | assert(rtn.return_code == 0) 42 | 43 | rtn = self.run_cmd("client install") 44 | assert(rtn.return_code == 0) 45 | -------------------------------------------------------------------------------- /python-dtf/tests/integration-device/client/test_client_upload.py: -------------------------------------------------------------------------------- 1 | # Android Device Testing Framework ("dtf") 2 | # Copyright 2013-2016 Jake Valletta (@jake_valletta) 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | """Integration tests for the "client upload" utility""" 17 | 18 | from __future__ import absolute_import 19 | import dtf.testutils as testutils 20 | 21 | 22 | PATH_TO_DTF_DATA = '/data/data/com.dtf.client' 23 | 24 | class ClientUploadTests(testutils.BasicIntegrationDeviceTest): 25 | 26 | """Wraper for integration tests""" 27 | 28 | def test_upload(self): 29 | 30 | """Do an upload""" 31 | 32 | data_file = testutils.DataFile("integration_client_upload_data") 33 | 34 | rtn = self.run_cmd("client upload %s" % str(data_file)) 35 | assert(rtn.return_code == 0) 36 | 37 | rtn = self.run_cmd("client execute \"rm %s/integration_client_upload_data\"" 38 | % PATH_TO_DTF_DATA) 39 | assert(rtn.return_code == 0) 40 | 41 | 42 | def test_upload_no_exist(self): 43 | 44 | """Upload non-existent file""" 45 | 46 | rtn = self.run_cmd("client upload TEST") 47 | assert(rtn.return_code == 255) 48 | 49 | def test_upload_path(self): 50 | 51 | """Do an upload to a path""" 52 | 53 | data_file = testutils.DataFile("integration_client_upload_data") 54 | 55 | rtn = self.run_cmd("client upload --path /data/data/com.dtf.client/test %s" 56 | % str(data_file)) 57 | assert(rtn.return_code == 0) 58 | 59 | rtn = self.run_cmd("client execute \"rm %s/integration_client_upload_data\"" 60 | % PATH_TO_DTF_DATA) 61 | assert(rtn.return_code == 0) 62 | 63 | def test_upload_not_installed(self): 64 | 65 | """Attempt to upload with non-existent APK""" 66 | 67 | rtn = self.run_cmd("client remove") 68 | assert(rtn.return_code == 0) 69 | 70 | data_file = testutils.DataFile("integration_client_upload_data") 71 | 72 | rtn = self.run_cmd("client upload %s" % str(data_file)) 73 | assert(rtn.return_code == 255) 74 | 75 | rtn = self.run_cmd("client install") 76 | assert(rtn.return_code == 0) 77 | -------------------------------------------------------------------------------- /python-dtf/tests/integration/archive/test_archive.py: -------------------------------------------------------------------------------- 1 | # Android Device Testing Framework ("dtf") 2 | # Copyright 2013-2016 Jake Valletta (@jake_valletta) 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | """Integration tests for archiving""" 17 | 18 | from __future__ import absolute_import 19 | import dtf.testutils as testutils 20 | import dtf.core.utils as utils 21 | 22 | import os.path 23 | 24 | class ArchiveTests(testutils.BasicIntegrationTest): 25 | 26 | """Wraper for integration tests""" 27 | 28 | def test_no_args(self): 29 | 30 | """Run with not args""" 31 | 32 | rtn = self.run_cmd("archive") 33 | 34 | assert(rtn.return_code == 0) 35 | 36 | 37 | def test_not_subcommand(self): 38 | 39 | """Try to call invalid sub command""" 40 | 41 | rtn = self.run_cmd("archive NOT_EXIST") 42 | 43 | assert(rtn.return_code == 0) 44 | 45 | def test_help(self): 46 | 47 | """Force the usage""" 48 | 49 | rtn = self.run_cmd("archive -h") 50 | 51 | assert(rtn.return_code == 0) 52 | 53 | def test_no_name(self): 54 | 55 | """Attempt create an archive using builtin name""" 56 | 57 | config = testutils.get_default_config() 58 | 59 | version_string = "android-17_XTS" 60 | zip_name = "%s.zip" % version_string 61 | config.set("Info", "version-string", version_string) 62 | 63 | self.update_config(config) 64 | 65 | rtn = self.run_cmd("archive create") 66 | 67 | assert(rtn.return_code == 0) 68 | assert(os.path.isfile(zip_name)) 69 | 70 | utils.delete_file(zip_name) 71 | 72 | def test_named(self): 73 | 74 | """Attempt to create an archive using custom name""" 75 | 76 | version_string = "android-17_XTS" 77 | zip_name = "%s.zip" % version_string 78 | 79 | rtn = self.run_cmd("archive create %s" % zip_name) 80 | 81 | assert(rtn.return_code == 0) 82 | assert(os.path.isfile(zip_name)) 83 | 84 | utils.delete_file(zip_name) 85 | -------------------------------------------------------------------------------- /python-dtf/tests/integration/binding/test_binding.py: -------------------------------------------------------------------------------- 1 | # Android Device Testing Framework ("dtf") 2 | # Copyright 2013-2016 Jake Valletta (@jake_valletta) 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | """Integration tests for the bindings""" 17 | 18 | from __future__ import absolute_import 19 | import dtf.testutils as testutils 20 | 21 | 22 | def test_no_args(): 23 | 24 | """Attempt to list bindings""" 25 | 26 | rtn = testutils.dtf("binding") 27 | assert(rtn.return_code == 0) 28 | 29 | 30 | def test_doesnt_exist(): 31 | 32 | """Attempt to get a binding that doesn't exist""" 33 | 34 | rtn = testutils.dtf("binding NON") 35 | assert(rtn.return_code == 255) 36 | 37 | 38 | def test_valid_bindings(): 39 | 40 | """Test all valid bindings""" 41 | 42 | binding_list = ['dtf_aapt', 'dtf_abe', 'dtf_apktool', 43 | 'dtf_axmlprinter2', 'dtf_baksmali', 44 | 'dtf_smali', 'dtf_dex2jar'] 45 | 46 | for binding in binding_list: 47 | 48 | rtn = testutils.dtf("binding %s" % binding) 49 | assert(rtn.return_code == 0) 50 | -------------------------------------------------------------------------------- /python-dtf/tests/integration/local/test_local.py: -------------------------------------------------------------------------------- 1 | # Android Device Testing Framework ("dtf") 2 | # Copyright 2013-2016 Jake Valletta (@jake_valletta) 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | """Integration tests for 'local' command""" 17 | 18 | from __future__ import absolute_import 19 | import dtf.testutils as testutils 20 | import dtf.core.utils as utils 21 | 22 | def test_no_args(): 23 | 24 | """Run with not args""" 25 | 26 | testutils.deploy_config(testutils.get_default_config()) 27 | 28 | example_local = "%s/example" % utils.LOCAL_MODULES_DIRECTORY 29 | utils.touch(example_local) 30 | 31 | rtn = testutils.dtf("local") 32 | 33 | testutils.undeploy() 34 | 35 | assert(rtn.return_code == 0) 36 | -------------------------------------------------------------------------------- /python-dtf/tests/integration/module/test_module.py: -------------------------------------------------------------------------------- 1 | # Android Device Testing Framework ("dtf") 2 | # Copyright 2013-2016 Jake Valletta (@jake_valletta) 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | """Integration tests for launching modules""" 17 | 18 | from __future__ import absolute_import 19 | import dtf.testutils as testutils 20 | 21 | class ModuleInstallTests(testutils.BasicIntegrationTest): 22 | 23 | """Wraper for integration tests""" 24 | 25 | def test_valid_python_execute(self): 26 | 27 | """Run module with default execute""" 28 | 29 | data_file = testutils.DataFile("integration_module_valid_mod") 30 | 31 | rtn = self.run_cmd("pm install --force --single module --install_name test_execute --name %s --auto" % str(data_file)) 32 | assert(rtn.return_code == 0) 33 | 34 | rtn = self.run_cmd("test_execute") 35 | 36 | assert(rtn.return_code == 0) 37 | 38 | def test_valid_python_sub_cmd(self): 39 | 40 | """Run module with valid sub_cmd""" 41 | 42 | data_file = testutils.DataFile("integration_module_valid_subs") 43 | 44 | rtn = self.run_cmd("pm install --force --single module --install_name test_sub --name %s --auto" % str(data_file)) 45 | assert(rtn.return_code == 0) 46 | 47 | rtn = self.run_cmd("test_sub test") 48 | 49 | assert(rtn.return_code == 0) 50 | 51 | def test_valid_python_wrong_sub(self): 52 | 53 | """Run module with not existant subcmd""" 54 | 55 | data_file = testutils.DataFile("integration_module_valid_subs") 56 | 57 | rtn = self.run_cmd("pm install --force --single module --install_name test_sub --name %s --auto" % str(data_file)) 58 | assert(rtn.return_code == 0) 59 | 60 | rtn = self.run_cmd("test_sub nope") 61 | 62 | assert(rtn.return_code == 241) 63 | 64 | def test_valid_python_raise_exception(self): 65 | 66 | """Run module and immediately raise an exception""" 67 | 68 | data_file = testutils.DataFile("integration_module_valid_raise") 69 | 70 | rtn = self.run_cmd("pm install --force --single module --install_name test_raise --name %s --auto" % str(data_file)) 71 | assert(rtn.return_code == 0) 72 | 73 | rtn = self.run_cmd("test_raise test") 74 | 75 | assert(rtn.return_code == 246) 76 | 77 | def test_valid_python_raise_kb_exception(self): 78 | 79 | """Run module and immediately raise a keyboard exception""" 80 | 81 | data_file = testutils.DataFile("integration_module_valid_kraise") 82 | 83 | rtn = self.run_cmd("pm install --force --single module --install_name test_kraise --name %s --auto" % str(data_file)) 84 | assert(rtn.return_code == 0) 85 | 86 | rtn = self.run_cmd("test_kraise test") 87 | 88 | assert(rtn.return_code == 245) 89 | 90 | # TODO: this cant be ran until --install_name is parsed correctly. 91 | #def test_invalid_python_missing_class(self): 92 | # 93 | # """Attempt to run module with missing class""" 94 | # 95 | # data_file = testutils.DataFile("integration_module_invalid_noclass") 96 | # 97 | # rtn = self.run_cmd("pm install --force --single module --install_name test_noclass --name %s" % str(data_file)) 98 | # assert(rtn.return_code == 0) 99 | # 100 | # rtn = self.run_cmd("test_noclass test") 101 | # 102 | # assert(rtn.return_code == 247) 103 | 104 | def test_invalid_python_no_exec_zero_args(self): 105 | 106 | """Attempt to run module with no args or exec""" 107 | 108 | data_file = testutils.DataFile("integration_module_invalid_noexecargs") 109 | 110 | rtn = self.run_cmd("pm install --force --single module --install_name test_noexecargs --name %s --auto" % str(data_file)) 111 | assert(rtn.return_code == 0) 112 | 113 | rtn = self.run_cmd("test_noexecargs test") 114 | 115 | assert(rtn.return_code == 242) 116 | -------------------------------------------------------------------------------- /python-dtf/tests/integration/pm/test_pm.py: -------------------------------------------------------------------------------- 1 | # Android Device Testing Framework ("dtf") 2 | # Copyright 2013-2016 Jake Valletta (@jake_valletta) 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | """Integration tests for the "pm" utility""" 17 | 18 | from __future__ import absolute_import 19 | import dtf.testutils as testutils 20 | 21 | 22 | class PmTests(testutils.BasicIntegrationTest): 23 | 24 | """Wraper for integration tests""" 25 | 26 | def test_no_args(self): 27 | 28 | """Running with no args""" 29 | 30 | rtn = self.run_cmd("pm") 31 | assert(rtn.return_code == 0) 32 | 33 | def test_not_subcommand(self): 34 | 35 | """Call invalid subcommand""" 36 | 37 | rtn = self.run_cmd("pm NOT_EXIST") 38 | assert(rtn.return_code == 0) 39 | -------------------------------------------------------------------------------- /python-dtf/tests/integration/pm/test_pm_delete.py: -------------------------------------------------------------------------------- 1 | # Android Device Testing Framework ("dtf") 2 | # Copyright 2013-2016 Jake Valletta (@jake_valletta) 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | """Integration tests for the "pm delete" utility""" 17 | 18 | from __future__ import absolute_import 19 | import dtf.testutils as testutils 20 | import dtf.core.utils as utils 21 | 22 | 23 | class PmDeletetTests(testutils.BasicIntegrationTest): 24 | 25 | """Wraper for integration tests""" 26 | 27 | def test_no_args(self): 28 | 29 | """Run with no args""" 30 | 31 | rtn = self.run_cmd("pm delete") 32 | assert(rtn.return_code == 255) 33 | 34 | def test_wrong_type(self): 35 | 36 | """Delete wrong type""" 37 | 38 | rtn = self.run_cmd("pm delete --name ye --type WRONG") 39 | assert(rtn.return_code == 254) 40 | 41 | def test_delete_binary(self): 42 | 43 | """Delete a binary""" 44 | 45 | data_file = testutils.DataFile("integration_pm_valid_zip.zip") 46 | 47 | rtn = self.run_cmd("pm install --zip %s" % str(data_file)) 48 | assert(rtn.return_code == 0) 49 | 50 | rtn = self.run_cmd("pm delete --name GenerateAIDL-1.0.jar --type binary", 51 | input_data="y\n") 52 | assert(rtn.return_code == 0) 53 | 54 | def test_delete_library(self): 55 | 56 | """Delete a library""" 57 | 58 | data_file = testutils.DataFile("integration_pm_valid_zip.zip") 59 | 60 | rtn = self.run_cmd("pm install --zip %s" % str(data_file)) 61 | assert(rtn.return_code == 0) 62 | 63 | rtn = self.run_cmd("pm delete --name Utils --type library", 64 | input_data="y\n") 65 | assert(rtn.return_code == 0) 66 | 67 | def test_delete_module(self): 68 | 69 | """Delete a module""" 70 | 71 | data_file = testutils.DataFile("integration_pm_valid_zip.zip") 72 | 73 | rtn = self.run_cmd("pm install --zip %s" % str(data_file)) 74 | assert(rtn.return_code == 0) 75 | 76 | rtn = self.run_cmd("pm delete --name apkget --type module", 77 | input_data="y\n") 78 | 79 | assert(rtn.return_code == 0) 80 | 81 | def test_delete_package(self): 82 | 83 | """Delete a package""" 84 | 85 | data_file = testutils.DataFile("integration_pm_valid_zip.zip") 86 | 87 | rtn = self.run_cmd("pm install --zip %s" % str(data_file)) 88 | assert(rtn.return_code == 0) 89 | 90 | rtn = self.run_cmd("pm delete --name HelloWorld_app --type package", 91 | input_data="y\n") 92 | assert(rtn.return_code == 0) 93 | -------------------------------------------------------------------------------- /python-dtf/tests/integration/pm/test_pm_export.py: -------------------------------------------------------------------------------- 1 | # Android Device Testing Framework ("dtf") 2 | # Copyright 2013-2016 Jake Valletta (@jake_valletta) 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | """Integration tests for the "pm export" utility""" 17 | 18 | from __future__ import absolute_import 19 | import os.path 20 | 21 | import dtf.testutils as testutils 22 | import dtf.core.utils as utils 23 | 24 | 25 | class PmExportTests(testutils.BasicIntegrationTest): 26 | 27 | """Wraper for integration tests""" 28 | 29 | def test_no_content(self): 30 | 31 | """Attempt to export nothing""" 32 | 33 | rtn = self.run_cmd("pm export test.zip") 34 | assert(rtn.return_code == 254) 35 | 36 | def test_existing_file(self): 37 | 38 | """Attempt to export to exisitng file""" 39 | 40 | utils.touch("test.zip") 41 | 42 | rtn = self.run_cmd("pm export test.zip") 43 | 44 | utils.delete_file("test.zip") 45 | 46 | assert(rtn.return_code == 255) 47 | 48 | def test_real_export(self): 49 | 50 | """Perform an export""" 51 | 52 | data_file = testutils.DataFile("integration_pm_valid_zip.zip") 53 | 54 | rtn = self.run_cmd("pm install --zip %s" % str(data_file)) 55 | assert(rtn.return_code == 0) 56 | 57 | rtn = self.run_cmd("pm export test.zip") 58 | assert(rtn.return_code == 0) 59 | assert(os.path.isfile("test.zip")) 60 | 61 | utils.delete_file("test.zip") 62 | -------------------------------------------------------------------------------- /python-dtf/tests/integration/pm/test_pm_list.py: -------------------------------------------------------------------------------- 1 | # Android Device Testing Framework ("dtf") 2 | # Copyright 2013-2016 Jake Valletta (@jake_valletta) 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | """Integration tests for the "pm list" utility""" 17 | 18 | from __future__ import absolute_import 19 | import dtf.testutils as testutils 20 | 21 | class PmListTests(testutils.BasicIntegrationTest): 22 | 23 | """Wraper for integration tests""" 24 | 25 | def test_no_args(self): 26 | 27 | """Running list with no args""" 28 | 29 | rtn = self.run_cmd("pm list") 30 | assert(rtn.return_code == 0) 31 | 32 | rtn = self.run_cmd("pm list -v") 33 | assert(rtn.return_code == 0) 34 | 35 | 36 | def test_quiet_verbose(self): 37 | 38 | """Try and fail to print verbose + quiet""" 39 | 40 | rtn = self.run_cmd("pm list -vq") 41 | assert(rtn.return_code == 255) 42 | 43 | 44 | def test_all_valid(self): 45 | 46 | """Print all types, with actual installed content""" 47 | 48 | data_file = testutils.DataFile("integration_pm_valid_zip.zip") 49 | 50 | rtn = self.run_cmd("pm install --zip %s" % str(data_file)) 51 | assert(rtn.return_code == 0) 52 | 53 | rtn = self.run_cmd("pm list") 54 | assert(rtn.return_code == 0) 55 | 56 | rtn = self.run_cmd("pm list -v") 57 | assert(rtn.return_code == 0) 58 | 59 | rtn = self.run_cmd("pm list -q") 60 | assert(rtn.return_code == 0) 61 | 62 | 63 | def test_binaries(self): 64 | 65 | """List only binaries""" 66 | 67 | rtn = self.run_cmd("pm list binaries") 68 | assert(rtn.return_code == 0) 69 | 70 | rtn = self.run_cmd("pm list binaries -v") 71 | assert(rtn.return_code == 0) 72 | 73 | rtn = self.run_cmd("pm list binaries -q") 74 | assert(rtn.return_code == 0) 75 | 76 | 77 | def test_libraries(self): 78 | 79 | """List only libraries""" 80 | 81 | rtn = self.run_cmd("pm list libraries") 82 | assert(rtn.return_code == 0) 83 | 84 | rtn = self.run_cmd("pm list libraries -v") 85 | assert(rtn.return_code == 0) 86 | 87 | rtn = self.run_cmd("pm list libraries -q") 88 | assert(rtn.return_code == 0) 89 | 90 | 91 | def test_modules(self): 92 | 93 | """List only modules""" 94 | 95 | rtn = self.run_cmd("pm list modules") 96 | assert(rtn.return_code == 0) 97 | 98 | rtn = self.run_cmd("pm list modules -v") 99 | assert(rtn.return_code == 0) 100 | 101 | rtn = self.run_cmd("pm list modules -q") 102 | assert(rtn.return_code == 0) 103 | 104 | 105 | def test_packages(self): 106 | 107 | """List only packages""" 108 | 109 | rtn = self.run_cmd("pm list packages") 110 | assert(rtn.return_code == 0) 111 | 112 | rtn = self.run_cmd("pm list packages -v") 113 | assert(rtn.return_code == 0) 114 | 115 | rtn = self.run_cmd("pm list packages -q") 116 | assert(rtn.return_code == 0) 117 | 118 | def test_list_invalid(self): 119 | 120 | """List a invalid type""" 121 | 122 | rtn = self.run_cmd("pm list BAD") 123 | assert(rtn.return_code == 253) 124 | -------------------------------------------------------------------------------- /python-dtf/tests/integration/pm/test_pm_purge.py: -------------------------------------------------------------------------------- 1 | # Android Device Testing Framework ("dtf") 2 | # Copyright 2013-2016 Jake Valletta (@jake_valletta) 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | """Integration tests for the "pm purge" utility""" 17 | 18 | from __future__ import absolute_import 19 | import dtf.testutils as testutils 20 | 21 | class PmPurgeTests(testutils.BasicIntegrationTest): 22 | 23 | """Wraper for integration tests""" 24 | 25 | def test_purge_cancel(self): 26 | 27 | """Run purge but cancel""" 28 | 29 | rtn = self.run_cmd("pm purge", input_data="n\n") 30 | assert(rtn.return_code == 0) 31 | 32 | def test_purge_go(self): 33 | 34 | """Run purge""" 35 | 36 | rtn = self.run_cmd("pm purge", input_data="y\n") 37 | assert(rtn.return_code == 0) 38 | -------------------------------------------------------------------------------- /python-dtf/tests/integration/pm/test_pm_repo.py: -------------------------------------------------------------------------------- 1 | # Android Device Testing Framework ("dtf") 2 | # Copyright 2013-2017 Jake Valletta (@jake_valletta) 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | """Integration tests for the "pm repo" utility""" 17 | 18 | from __future__ import absolute_import 19 | import dtf.testutils as testutils 20 | 21 | class PmRepoTests(testutils.BasicIntegrationTest): 22 | 23 | """Wraper for integration tests""" 24 | 25 | def test_no_args(self): 26 | 27 | """Running repo with no args""" 28 | 29 | rtn = self.run_cmd("pm repo") 30 | assert(rtn.return_code == 0) 31 | 32 | def test_invalid_cmd(self): 33 | 34 | """Run repo with invalid cmd""" 35 | 36 | rtn = self.run_cmd("pm repo NOTHING") 37 | assert(rtn.return_code == 255) 38 | 39 | def test_repo_add_valid(self): 40 | 41 | """Try to readd a repo with same name""" 42 | 43 | rtn = self.run_cmd("pm repo add core-mods https://somethingsilly.com") 44 | assert(rtn.return_code == 0) 45 | 46 | 47 | def test_repo_add_wrong_args(self): 48 | 49 | """Run add with incorrect args""" 50 | 51 | rtn = self.run_cmd("pm repo add") 52 | assert(rtn.return_code == 255) 53 | 54 | def test_repo_add_invalid_url(self): 55 | 56 | """Try to add invalid repo URL""" 57 | 58 | rtn = self.run_cmd("pm repo add core-mods somethingsilly.com") 59 | assert(rtn.return_code == 254) 60 | 61 | def test_repo_add_already_exists(self): 62 | 63 | """Try to re-add a repo with same name""" 64 | 65 | rtn = self.run_cmd("pm repo add core-mods https://somethingsilly.com") 66 | assert(rtn.return_code == 0) 67 | 68 | rtn = self.run_cmd("pm repo add core-mods https://somethingsilly.com") 69 | assert(rtn.return_code == 253) 70 | 71 | def test_repo_remove_valid(self): 72 | 73 | """Add then remove a repo""" 74 | 75 | rtn = self.run_cmd("pm repo add core-mods https://somethingsilly.com") 76 | assert(rtn.return_code == 0) 77 | 78 | rtn = self.run_cmd("pm repo remove core-mods") 79 | assert(rtn.return_code == 0) 80 | 81 | def test_repo_remove_wrong_args(self): 82 | 83 | """Run remove with incorrect args""" 84 | 85 | rtn = self.run_cmd("pm repo remove") 86 | assert(rtn.return_code == 255) 87 | 88 | def test_repo_remove_nonexist(self): 89 | 90 | """Attempt to remove not exist repo""" 91 | 92 | rtn = self.run_cmd("pm repo remove silly") 93 | assert(rtn.return_code == 253) 94 | 95 | def test_repo_list_empty(self): 96 | 97 | """List no repos""" 98 | 99 | rtn = self.run_cmd("pm repo list") 100 | assert(rtn.return_code == 0) 101 | 102 | def test_repo_list_valid(self): 103 | 104 | """List no repos""" 105 | 106 | rtn = self.run_cmd("pm repo add mods-core https://silly.com") 107 | assert(rtn.return_code == 0) 108 | 109 | rtn = self.run_cmd("pm repo list") 110 | assert(rtn.return_code == 0) 111 | -------------------------------------------------------------------------------- /python-dtf/tests/integration/prop/test_prop.py: -------------------------------------------------------------------------------- 1 | # Android Device Testing Framework ("dtf") 2 | # Copyright 2013-2016 Jake Valletta (@jake_valletta) 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | """Integration tests for the "prop" utility""" 17 | 18 | from __future__ import absolute_import 19 | import dtf.testutils as testutils 20 | 21 | 22 | def test_no_args(): 23 | 24 | """Running with no args""" 25 | 26 | testutils.deploy_config(testutils.get_default_config()) 27 | 28 | rtn = testutils.dtf("prop") 29 | 30 | testutils.undeploy() 31 | 32 | assert(rtn.return_code == 0) 33 | 34 | 35 | def test_not_subcommand(): 36 | 37 | """Call invalid subcommand""" 38 | 39 | testutils.deploy_config(testutils.get_default_config()) 40 | 41 | rtn = testutils.dtf("prop NON_EXIST") 42 | 43 | testutils.undeploy() 44 | 45 | assert(rtn.return_code == 0) 46 | -------------------------------------------------------------------------------- /python-dtf/tests/integration/prop/test_prop_del.py: -------------------------------------------------------------------------------- 1 | # Android Device Testing Framework ("dtf") 2 | # Copyright 2013-2016 Jake Valletta (@jake_valletta) 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | """Integration tests for the "prop del" utility""" 17 | 18 | from __future__ import absolute_import 19 | import dtf.testutils as testutils 20 | 21 | 22 | def test_no_args(): 23 | 24 | """Running del with no args""" 25 | 26 | testutils.deploy_config(testutils.get_default_config()) 27 | 28 | rtn = testutils.dtf("prop del") 29 | 30 | testutils.undeploy() 31 | 32 | assert(rtn.return_code == 0) 33 | 34 | 35 | def test_del_valid_prop(): 36 | 37 | """Delete a valid property""" 38 | 39 | config = testutils.get_default_config() 40 | config.set("Info", "magic", "AbraKadabra") 41 | 42 | testutils.deploy_config(config) 43 | 44 | rtn = testutils.dtf("prop del Info magic") 45 | 46 | testutils.undeploy() 47 | 48 | assert(rtn.return_code == 0) 49 | -------------------------------------------------------------------------------- /python-dtf/tests/integration/prop/test_prop_dump.py: -------------------------------------------------------------------------------- 1 | # Android Device Testing Framework ("dtf") 2 | # Copyright 2013-2016 Jake Valletta (@jake_valletta) 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | """Integration tests for the "prop dump" utility""" 17 | 18 | from __future__ import absolute_import 19 | import dtf.testutils as testutils 20 | 21 | 22 | def test_no_args(): 23 | 24 | """Running dump with no args""" 25 | 26 | testutils.deploy_config(testutils.get_default_config()) 27 | 28 | rtn = testutils.dtf("prop dump") 29 | 30 | testutils.undeploy() 31 | 32 | assert(rtn.return_code == 0) 33 | -------------------------------------------------------------------------------- /python-dtf/tests/integration/prop/test_prop_get.py: -------------------------------------------------------------------------------- 1 | # Android Device Testing Framework ("dtf") 2 | # Copyright 2013-2016 Jake Valletta (@jake_valletta) 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | """Integration tests for the "prop get" utility""" 17 | 18 | from __future__ import absolute_import 19 | import dtf.testutils as testutils 20 | 21 | 22 | def test_no_args(): 23 | 24 | """Running get with no args""" 25 | 26 | testutils.deploy_config(testutils.get_default_config()) 27 | 28 | rtn = testutils.dtf("prop get") 29 | 30 | testutils.undeploy() 31 | 32 | assert(rtn.return_code == 0) 33 | 34 | 35 | def test_get_valid_prop(): 36 | 37 | """Get an existing property""" 38 | 39 | testutils.deploy_config(testutils.get_default_config()) 40 | 41 | rtn = testutils.dtf("prop get Info sdk") 42 | 43 | testutils.undeploy() 44 | 45 | assert(rtn.return_code == 0) 46 | 47 | 48 | def test_get_invalid_prop(): 49 | 50 | """Get a non-existing property""" 51 | 52 | testutils.deploy_config(testutils.get_default_config()) 53 | 54 | rtn = testutils.dtf("prop get Info magic") 55 | 56 | testutils.undeploy() 57 | 58 | assert(rtn.return_code == 255) 59 | -------------------------------------------------------------------------------- /python-dtf/tests/integration/prop/test_prop_set.py: -------------------------------------------------------------------------------- 1 | # Android Device Testing Framework ("dtf") 2 | # Copyright 2013-2016 Jake Valletta (@jake_valletta) 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | """Integration tests for the "prop set" utility""" 17 | 18 | from __future__ import absolute_import 19 | import dtf.testutils as testutils 20 | 21 | 22 | def test_no_args(): 23 | 24 | """Running set with no args""" 25 | 26 | testutils.deploy_config(testutils.get_default_config()) 27 | 28 | rtn = testutils.dtf("prop set") 29 | 30 | testutils.undeploy() 31 | 32 | assert(rtn.return_code == 0) 33 | 34 | 35 | def test_set_a_prop(): 36 | 37 | """Set an arbitrary property""" 38 | 39 | testutils.deploy_config(testutils.get_default_config()) 40 | 41 | rtn = testutils.dtf("prop set Info magic AbraKadabra") 42 | 43 | testutils.undeploy() 44 | 45 | assert(rtn.return_code == 0) 46 | -------------------------------------------------------------------------------- /python-dtf/tests/integration/prop/test_prop_test.py: -------------------------------------------------------------------------------- 1 | # Android Device Testing Framework ("dtf") 2 | # Copyright 2013-2016 Jake Valletta (@jake_valletta) 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | """Integration tests for the "prop test" utility""" 17 | 18 | from __future__ import absolute_import 19 | import dtf.testutils as testutils 20 | 21 | 22 | def test_no_args(): 23 | 24 | """Running test with no args""" 25 | 26 | testutils.deploy_config(testutils.get_default_config()) 27 | 28 | rtn = testutils.dtf("prop test") 29 | 30 | testutils.undeploy() 31 | 32 | assert(rtn.return_code == 0) 33 | 34 | 35 | def test_test_valid_prop(): 36 | 37 | """Test a valid property""" 38 | 39 | testutils.deploy_config(testutils.get_default_config()) 40 | 41 | rtn = testutils.dtf("prop test Info sdk") 42 | 43 | testutils.undeploy() 44 | 45 | assert(rtn.return_code == 1) 46 | 47 | def test_test_invalid_prop(): 48 | 49 | """Test an invalid property""" 50 | 51 | testutils.deploy_config(testutils.get_default_config()) 52 | 53 | rtn = testutils.dtf("prop test Info magic") 54 | 55 | testutils.undeploy() 56 | 57 | assert(rtn.return_code == 0) 58 | 59 | -------------------------------------------------------------------------------- /python-dtf/tests/integration/reset/test_reset.py: -------------------------------------------------------------------------------- 1 | # Android Device Testing Framework ("dtf") 2 | # Copyright 2013-2016 Jake Valletta (@jake_valletta) 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | """Integration tests for "reset" command""" 17 | 18 | from __future__ import absolute_import 19 | import dtf.testutils as testutils 20 | 21 | 22 | def test_reset_bail(): 23 | 24 | """Attempt a reset but decline""" 25 | 26 | testutils.deploy_config(testutils.get_default_config()) 27 | 28 | rtn = testutils.dtf("reset", input_data="n\n") 29 | 30 | testutils.undeploy() 31 | 32 | assert(rtn.return_code == 255) 33 | 34 | 35 | def test_reset_real(): 36 | 37 | """Perform a reset""" 38 | 39 | testutils.deploy_config(testutils.get_default_config()) 40 | 41 | rtn = testutils.dtf("reset", input_data="y\n") 42 | 43 | testutils.undeploy() 44 | 45 | assert(rtn.return_code == 0) 46 | -------------------------------------------------------------------------------- /python-dtf/tests/integration/test_dtf.py: -------------------------------------------------------------------------------- 1 | # Android Device Testing Framework ("dtf") 2 | # Copyright 2013-2016 Jake Valletta (@jake_valletta) 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | """Integration tests for the general launcher""" 17 | 18 | from __future__ import absolute_import 19 | import dtf.testutils as testutils 20 | 21 | 22 | def test_dtf(): 23 | 24 | """Just attempt to run dtf""" 25 | 26 | rtn = testutils.dtf("") 27 | assert(rtn.return_code == 255) 28 | 29 | 30 | def test_version(): 31 | 32 | """Attempt to obtain version""" 33 | 34 | rtn = testutils.dtf("--version") 35 | assert(rtn.return_code == 0) 36 | 37 | rtn = testutils.dtf("-v") 38 | assert(rtn.return_code == 0) 39 | 40 | rtn = testutils.dtf("version") 41 | assert(rtn.return_code == 0) 42 | 43 | 44 | def test_help(): 45 | 46 | """Attempt to print help/useage""" 47 | 48 | rtn = testutils.dtf("--help") 49 | assert(rtn.return_code == 0) 50 | 51 | rtn = testutils.dtf("-h") 52 | assert(rtn.return_code == 0) 53 | 54 | rtn = testutils.dtf("help") 55 | assert(rtn.return_code == 0) 56 | 57 | def test_non_project(): 58 | 59 | """Attempt to run a built-in without a .dtfini""" 60 | 61 | rtn = testutils.dtf("archive") 62 | assert(rtn.return_code == 253) 63 | 64 | 65 | def test_python_precheck_sdk_missing(): 66 | 67 | """Attempt to run python module with missing SDK""" 68 | 69 | testutils.deploy_config_raw("") 70 | 71 | rtn = testutils.dtf("archive") 72 | 73 | testutils.undeploy() 74 | 75 | assert(rtn.return_code == 248) 76 | 77 | 78 | def test_python_load_imp_exception(): 79 | 80 | """Attempt to run builtin and fail to parse load_imp""" 81 | 82 | testutils.deploy_config_raw("") 83 | 84 | rtn = testutils.dtf("status") 85 | 86 | testutils.undeploy() 87 | 88 | assert(rtn.return_code == 247) 89 | -------------------------------------------------------------------------------- /python-dtf/tests/unit/test_colors.py: -------------------------------------------------------------------------------- 1 | # Android Device Testing Framework ("dtf") 2 | # Copyright 2013-2016 Jake Valletta (@jake_valletta) 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | """pytest for using dtf coloring""" 17 | 18 | from __future__ import absolute_import 19 | from __future__ import print_function 20 | import dtf.colors as colors 21 | import dtf.testutils as testutils 22 | 23 | TAG = 'test_colors' 24 | 25 | 26 | def test_error(): 27 | 28 | """Log an error message""" 29 | 30 | print("This message is an %s" % colors.error("error.")) 31 | 32 | 33 | def test_warning(): 34 | 35 | """Log an warning message""" 36 | 37 | print("This message is a %s" % colors.warning("warning.")) 38 | 39 | 40 | def test_info(): 41 | 42 | """Log an info message""" 43 | 44 | print("This message is a %s" % colors.info("info message.")) 45 | 46 | 47 | def test_verbose(): 48 | 49 | """Log an verbose message""" 50 | 51 | print("This message is a %s" % colors.verbose("verbose message.")) 52 | 53 | 54 | def test_debug(): 55 | 56 | """Log an debug message""" 57 | 58 | print("This message is a %s" % colors.debug("debug message.")) 59 | 60 | def test_bold(): 61 | 62 | """Log a bolded message""" 63 | 64 | print("This message is %s" % colors.bold("important!")) 65 | -------------------------------------------------------------------------------- /python-dtf/tests/unit/test_included.py: -------------------------------------------------------------------------------- 1 | # Android Device Testing Framework ("dtf") 2 | # Copyright 2013-2016 Jake Valletta (@jake_valletta) 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | """Unit tests for testing included wrappers""" 17 | 18 | from __future__ import absolute_import 19 | import dtf.included as included 20 | import dtf.core.utils as utils 21 | import dtf.testutils as testutils 22 | 23 | 24 | def test_aapt(): 25 | 26 | """Run test aapt command""" 27 | data_file = testutils.DataFile("hello-world.apk") 28 | 29 | stdout, stderr, rtn = included.aapt("d badging %s" % str(data_file)) 30 | 31 | assert rtn == 0 32 | 33 | def test_apktool(): 34 | 35 | """Run test apktool command""" 36 | 37 | data_file = testutils.DataFile("hello-world.apk") 38 | 39 | stdout, stderr, rtn = included.apktool("d %s" % str(data_file)) 40 | 41 | utils.delete_tree("hello-world") 42 | 43 | assert rtn == 0 44 | 45 | def test_smali(): 46 | 47 | """Run test smali/baksmali command""" 48 | 49 | data_file = testutils.DataFile("hello-world.apk") 50 | 51 | stdout, stderr, rtn_bak = included.baksmali("-o out %s" % str(data_file)) 52 | stdout, stderr, rtn_smali = included.smali("-o classes.dex out") 53 | 54 | utils.delete_tree("out") 55 | utils.delete_file("classes.dex") 56 | 57 | assert rtn_bak == 0 58 | assert rtn_smali == 0 59 | 60 | 61 | def test_axmlprinter2(): 62 | 63 | """Run test axmlprinter2 command""" 64 | 65 | data_file = testutils.DataFile("valid_android_manifest.xml") 66 | out_file = "out.xml" 67 | 68 | rtn = included.axmlprinter2(str(data_file), out_file) 69 | 70 | utils.delete_file(out_file) 71 | 72 | assert rtn == 0 73 | -------------------------------------------------------------------------------- /release/android-dtf_all.deb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/android-dtf/dtf/a761ace77cea051bfb88d56df65ae6b83f664480/release/android-dtf_all.deb -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | colored==1.3.5 2 | cov-core==1.15.0 3 | coverage==4.2 4 | flake8==3.5.0 5 | lxml==4.1.0 6 | pylint==1.7.4 7 | py==1.4.34 8 | pytest==3.2.3 9 | pytest-runner==3.0 10 | wheel==0.29.0 11 | semantic_version==2.6.0 12 | requests==2.20.0 13 | configparser==3.5.0 14 | -------------------------------------------------------------------------------- /uninstall_1_3.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Android Device Testing Framework ("dtf") 3 | # Copyright 2013-2016 Jake Valletta (@jake_valletta) 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | # Uninstaller script to remove dtf 1.3.0 18 | # Usage: sudo ./uninstall_1_3.sh 19 | 20 | # Delete the bash completion 21 | echo "Removing bash completion..." 22 | rm /etc/bash_completion.d/dtf_bash_completion.sh 23 | 24 | 25 | echo "Removing launcher..." 26 | # Delete the launcher 27 | rm /usr/local/bin/dtf 28 | 29 | 30 | echo "Removing Python library..." 31 | # Delete the library 32 | sudo pip uninstall dtf 33 | rm -rf /usr/local/lib/python2.7/dist-packages/dtf 34 | 35 | echo "Uninstall complete!" 36 | -------------------------------------------------------------------------------- /wait_for_emulator: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Waits for emulator to completely boot to lock screen 4 | # Used to run tests on Travis CI (#137) 5 | # Originally written by Ralf Kistner , but placed in the public domain 6 | # Recommended by Travis docs - http://docs.travis-ci.com/user/languages/android/#How-to-Create-and-Start-an-Emulator 7 | # Source (under Apache 2.0) - https://github.com/andrewhr/rxjava-android-example/blob/master/ci/wait_for_emulator 8 | 9 | set +e 10 | 11 | bootanim="" 12 | failcounter=0 13 | timeout_in_sec=360 14 | 15 | echo "Using adb: $(which adb)" 16 | 17 | until [[ "$bootanim" =~ "stopped" ]]; do 18 | bootanim=`adb -e shell getprop init.svc.bootanim 2>&1 &` 19 | if [[ "$bootanim" =~ "device not found" || "$bootanim" =~ "device offline" 20 | || "$bootanim" =~ "running" ]]; then 21 | let "failcounter += 1" 22 | echo "Waiting for emulator to start" 23 | if [[ $failcounter -gt timeout_in_sec ]]; then 24 | echo "Timeout ($timeout_in_sec seconds) reached; failed to start emulator" 25 | exit 1 26 | fi 27 | fi 28 | sleep 1 29 | done 30 | 31 | echo "Emulator is ready" 32 | --------------------------------------------------------------------------------