From 081e65d06f722a4a9d6bb22e445da7f3dc15820d Mon Sep 17 00:00:00 2001 From: Nicolas Catania Date: Fri, 9 Oct 2009 21:17:27 -0700 Subject: [PATCH] New interactive functions to send commands to a device. This is still a bit crude but now we can remount,sync,reboot and flash a device from emacs. Support product aliases. --- ide/emacs/android-common.el | 154 +++++++++++++++++++++++++++++++++++++------- ide/emacs/android-host.el | 114 ++++++++++++++++++++++++++++++++ 2 files changed, 246 insertions(+), 22 deletions(-) create mode 100644 ide/emacs/android-host.el diff --git a/ide/emacs/android-common.el b/ide/emacs/android-common.el index a4cd1e58..8988598c 100644 --- a/ide/emacs/android-common.el +++ b/ide/emacs/android-common.el @@ -1,20 +1,34 @@ -;;; -;;; Copyright (C) 2009 The Android Open Source Project -;;; -;;; Licensed under the Apache License, Version 2.0 (the "License"); -;;; you may not use this file except in compliance with the License. -;;; You may obtain a copy of the License at -;;; -;;; http://www.apache.org/licenses/LICENSE-2.0 -;;; -;;; Unless required by applicable law or agreed to in writing, software -;;; distributed under the License is distributed on an "AS IS" BASIS, -;;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -;;; See the License for the specific language governing permissions and -;;; limitations under the License. - -;;; Variables to customize and common function for the android build -;;; support in Emacs. +;;; android-common.el --- Common functions/variables to dev Android in Emacs. +;; +;; Copyright (C) 2009 The Android Open Source Project +;; +;; Licensed under the Apache License, Version 2.0 (the "License"); +;; you may not use this file except in compliance with the License. +;; You may obtain a copy of the License at +;; +;; http://www.apache.org/licenses/LICENSE-2.0 +;; +;; Unless required by applicable law or agreed to in writing, software +;; distributed under the License is distributed on an "AS IS" BASIS, +;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +;; See the License for the specific language governing permissions and +;; limitations under the License. + +;;; Commentary: +;; +;; Variables to customize and common functions for the Android build +;; support in Emacs. +;; There should be no interactive function in this module. +;; +;; You need to have a proper buildspec.mk file in your root directory +;; for this module to work (see $TOP/build/buildspec.mk.default). +;; If the path the product's files/image uses an a product alias, you +;; need to add a mapping in `android-product-alias-map'. For instance +;; if TARGET_PRODUCT is foo but the build directory is out/target/product/bar, +;; you need to add a mapping Target:foo -> Alias:bar +;; + +;;; Code: (defgroup android nil "Support for android development in Emacs." @@ -26,26 +40,122 @@ :type 'integer :group 'android) +;;;###autoload +(defcustom android-product-alias-map nil + "Alist between product targets (declared in buildspec.mk) and actual + product build directory used by `android-product'. + +For instance if TARGET_PRODUCT is 'foo' but the build directory + is 'out/target/product/bar', you need to add a mapping Target:foo -> Alias:bar." + :type '(repeat (list (string :tag "Target") + (string :tag "Alias"))) + :group 'android) + (defun android-find-build-tree-root () "Ascend the current path until the root of the android build tree is found. Similarly to the shell functions in envsetup.sh, for the root both ./Makefile and ./build/core/envsetup.mk are exiting files. -Return the root of the build tree. Signal an error if not found." +Return the root of the build tree. Signal an error if not found." (let ((default-directory default-directory)) (while (and (> (length default-directory) 2) - (not (file-exists-p (concat default-directory "Makefile"))) - (not (file-exists-p (concat default-directory "build/core/envsetup.mk")))) + (not (file-exists-p (concat default-directory + "Makefile"))) + (not (file-exists-p (concat default-directory + "build/core/envsetup.mk")))) (setq default-directory (substring default-directory 0 (string-match "[^/]+/$" default-directory)))) (if (> (length default-directory) 2) default-directory - (error "Not in a valid android tree.")))) + (error "Not in a valid android tree")))) (defun android-project-p () -"Return nil if not in an android build tree." + "Return nil if not in an android build tree." (condition-case nil (android-find-build-tree-root) (error nil))) +(defun android-host () + "Return the - string (e.g linux-x86). +Only linux and darwin on x86 architectures are supported." + (or (string-match "x86" system-configuration) + (string-match "i386" system-configuration) + (error "Unknown arch")) + (or (and (string-match "darwin" system-configuration) "darwin-x86") + (and (string-match "linux" system-configuration) "linux-x86") + (error "Unknown system"))) + +(defun android-product () + "Return the product built according to the buildspec.mk. +You must have buildspec.mk file in the top directory. + +Additional product aliases can be listed in `android-product-alias-map' +if the product actually built is different from the one listed +in buildspec.mk" + (save-excursion + (let* ((buildspec (concat (android-find-build-tree-root) "buildspec.mk")) + (product (with-current-buffer (find-file-noselect buildspec) + (goto-char (point-min)) + (search-forward "TARGET_PRODUCT:=") + (buffer-substring-no-properties (point) + (scan-sexps (point) 1)))) + (alias (assoc product android-product-alias-map))) + ; Post processing, adjust the names. + (if (not alias) + product + (nth 1 alias))))) + +(defun android-product-path () + "Return the full path to the product directory. + +Additional product aliases can be added in `android-product-alias-map' +if the product actually built is different from the one listed +in buildspec.mk" + (let ((path (concat (android-find-build-tree-root) "out/target/product/" + (android-product)))) + (when (not (file-exists-p path)) + (error (format "%s does not exist. If product %s maps to another one, +add an entry to android-product-map." path (android-product)))) + path)) + +(defun android-find-host-bin (binary) + "Return the full path to the host BINARY. +Binaries don't depend on the device, just on the host type. +Try first to locate BINARY in the out/host tree. Fallback using +the shell exec PATH setup." + (if (android-project-p) + (let ((path (concat (android-find-build-tree-root) "out/host/" + (android-host) "/bin/" binary))) + (if (file-exists-p path) + path + (error (concat binary " is missing.")))) + (executable-find binary))) + +(defun android-adb () + "Return the path to the adb executable. +If not in the build tree use the PATH env variable." + (android-find-host-bin "adb")) + +(defun android-fastboot () + "Return the path to the fastboot executable. +If not in the build tree use the PATH env variable." + ; For fastboot -p is the name of the product, *not* the full path to + ; its directory like adb requests sometimes. + (concat (android-find-host-bin "fastboot") " -p " (android-product))) + +(defun android-adb-command (command &optional product) + "Execute 'adb COMMAND'. +If the optional PRODUCT is not nil, -p (android-product-path) is used +when adb is invoked." + (if product + (shell-command (concat (android-adb) " -p " (android-product-path) + " " command)) + (shell-command (concat (android-adb) " " command)))) + +(defun android-adb-shell-command (command) + "Execute 'adb shell COMMAND'." + (android-adb-command (concat " shell " command))) + (provide 'android-common) + +;;; android-common.el ends here diff --git a/ide/emacs/android-host.el b/ide/emacs/android-host.el new file mode 100644 index 00000000..9b9fe9d5 --- /dev/null +++ b/ide/emacs/android-host.el @@ -0,0 +1,114 @@ +;;; android-host.el --- Module to use host binaries from an Android dev tree. +;; +;; Copyright (C) 2009 The Android Open Source Project +;; +;; Licensed under the Apache License, Version 2.0 (the "License"); +;; you may not use this file except in compliance with the License. +;; You may obtain a copy of the License at +;; +;; http://www.apache.org/licenses/LICENSE-2.0 +;; +;; Unless required by applicable law or agreed to in writing, software +;; distributed under the License is distributed on an "AS IS" BASIS, +;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +;; See the License for the specific language governing permissions and +;; limitations under the License. + +;;; Commentary: +;; +;; This module defines interactive functions to send the most common +;; commands to a device. +;; +;; Currently only one device is supported. +;; +;; In your .emacs load this file (e.g (require 'android-host)) then +;; you can either create new shortcuts e.g: +;; +;; (global-set-key [f8] 'android-adb-sync) +;; +;; or rely on autocompletion M-x and-sync will expand to +;; M-x android-adb-sync +;; +;; By default the following key bindings are active: +;; C-x a a android-adb-root +;; C-x a r android-adb-remount +;; C-x a s android-adb-sync +;; C-x a b android-adb-shell-reboot-bootloader +;; C-x a f android-fastboot-flashall +;; +;; android-fastboot-flashall is still work in progress, check the +;; associated buffer (*Fastboot*) for errors when you use it. + +;;; Code: + +(require 'android-common) + +(defvar android-host-command-map (make-sparse-keymap)) + +(defun android-host-key-prefix-set (var val) + "Bind the keys shortcuts to the functions.i" + ;; TODO: This should go in a minor mode keymap instead of + ;; messing with the global one. + (define-key global-map (read-kbd-macro val) android-host-command-map) + (custom-set-default var val)) + +(let ((map android-host-command-map)) + (define-key map (kbd "a") 'android-adb-root) + (define-key map (kbd "r") 'android-adb-remount) + (define-key map (kbd "s") 'android-adb-sync) + (define-key map (kbd "b") 'android-adb-shell-reboot-bootloader) + (define-key map (kbd "f") 'android-fastboot-flashall)) + +(defcustom android-host-key-prefix "C-x a" + "Prefix keystrokes for Android commands." + :group 'android + :type 'string + :set 'android-host-key-prefix-set) + +(defun android-adb-remount () + "Execute 'adb remount'." + (interactive) + (android-adb-command "remount")) + +(defun android-adb-root () + "Execute 'adb root'." + (interactive) + (android-adb-command "root")) + +(defun android-adb-shell-reboot-bootloader () + "Execute 'adb shell reboot bootloader'." + (interactive) + (android-adb-shell-command "reboot bootloader")) + +(defun android-adb-sync () + "Execute 'adb sync'." + (interactive) + (android-adb-command "sync" 'p)) + +(defun android-fastboot-sentinel (process event) + "Called when the fastboot process is done." + ;; TODO: Should barf if the last lines are not: + ;; OKAY + ;; rebooting... + (princ + (format "Process: %s had the event `%s'" process event))) + +(defun android-fastboot-flashall (arg) + "Execute 'fastboot -p flashall'. + +With no ARG, don't wipe the user data. +With ARG, wipe the user data." + (interactive "P") + (when (get-buffer "*Fastboot*") + (with-current-buffer "*Fastboot*" (erase-buffer))) + (let ((proc + (if arg + (start-process-shell-command + "fastboot" "*Fastboot*" (concat (android-fastboot) " flashall -w")) + (start-process-shell-command + "fastboot" "*Fastboot*" (concat (android-fastboot) " flashall"))))) + (set-process-sentinel proc 'android-fastboot-sentinel))) + + +(provide 'android-host) +;;; android-host.el ends here -- 2.11.0