Merge "TBR: Revert "devtools: Bump timeout for v23-proxy-integration-test to 30 min.""
diff --git a/data/COPYRIGHT b/data/COPYRIGHT
index 3c28650..a26470e 100644
--- a/data/COPYRIGHT
+++ b/data/COPYRIGHT
@@ -1,3 +1,3 @@
-Copyright 2015 The Vanadium Authors. All rights reserved.
+Copyright [YEAR] The Vanadium Authors. All rights reserved.
 Use of this source code is governed by a BSD-style
 license that can be found in the LICENSE file.
\ No newline at end of file
diff --git a/jiri-copyright/copyright.go b/jiri-copyright/copyright.go
index 38a2792..cb71550 100644
--- a/jiri-copyright/copyright.go
+++ b/jiri-copyright/copyright.go
@@ -20,7 +20,9 @@
 	"os"
 	"path/filepath"
 	"regexp"
+	"strconv"
 	"strings"
+	"time"
 
 	"v.io/jiri"
 	"v.io/jiri/collect"
@@ -421,7 +423,8 @@
 	if err != nil {
 		return nil, err
 	}
-	result.Copyright = string(bytes)
+	currentYear := strconv.Itoa(time.Now().Year())
+	result.Copyright = strings.Replace(string(bytes), "[YEAR]", currentYear, 1)
 	return &result, nil
 }
 
diff --git a/jiri-profile-v23/mojo_profile/mojo.go b/jiri-profile-v23/mojo_profile/mojo.go
index e4d043d..229404b 100644
--- a/jiri-profile-v23/mojo_profile/mojo.go
+++ b/jiri-profile-v23/mojo_profile/mojo.go
@@ -10,6 +10,7 @@
 	"flag"
 	"fmt"
 	"io/ioutil"
+	"os"
 	"path/filepath"
 	"strings"
 
@@ -230,7 +231,32 @@
 				sdkVersion:                  "39488b961eb9dca8c6ca4a2cc0d693dd13db29e3",
 				androidPlatformToolsVersion: "2219198",
 			},
-		}, "7"),
+			"8": &versionSpec{
+				serviceNames: []string{
+					"authenticating_url_loader_interceptor.mojo",
+					"compositor_service.mojo",
+					"dart_content_handler.mojo",
+					"debugger.mojo",
+					"files.mojo",
+					"input_manager_service.mojo",
+					"launcher.mojo",
+					"view_manager_service.mojo",
+					"tracing.mojo",
+				},
+				serviceNamesAndroid: []string{
+					"shortcut.mojo",
+				},
+				serviceNamesLinux: []string{
+					"authentication.mojo",
+				},
+				buildVersionAndroid:         "92b330f6dedb4d880eb66e384a28b1a4de2f6ba2",
+				buildVersionLinux:           "92b330f6dedb4d880eb66e384a28b1a4de2f6ba2",
+				devtoolsVersion:             "6a6098eb787ea88af5ef8e2978074ad57ce6ebeb",
+				networkServiceVersion:       "0a814ed5512598e595c0ae7975a09d90a7a54e90",
+				sdkVersion:                  "465117ff5f34a8ef48b6a94d57f081e3c8e77ca5",
+				androidPlatformToolsVersion: "2219198",
+			},
+		}, "8"),
 	}
 	profilesmanager.Register(m)
 }
@@ -419,14 +445,15 @@
 func (m *Manager) installMojoSdk(jirix *jiri.X, outDir string) error {
 	fn := func() error {
 		seq := jirix.NewSeq()
+		srcDir := filepath.Join(outDir, "src")
 		// TODO(nlacasse): At some point Mojo needs to change the structure of
 		// their repo so that go packages occur with correct paths. Until then
 		// we'll clone into src/mojo/public so that go import paths work.
-		repoDst := filepath.Join(outDir, "src", "mojo", "public")
+		publicDir := filepath.Join(srcDir, "mojo", "public")
 		seq.
-			MkdirAll(repoDst, profilesutil.DefaultDirPerm).
-			Pushd(repoDst).
-			Call(func() error { return gitutil.New(jirix.NewSeq()).CloneRecursive(mojoSdkRemote, repoDst) }, "git clone --recursive %s", mojoSdkRemote).
+			MkdirAll(publicDir, profilesutil.DefaultDirPerm).
+			Pushd(publicDir).
+			Call(func() error { return gitutil.New(jirix.NewSeq()).CloneRecursive(mojoSdkRemote, publicDir) }, "git clone --recursive %s", mojoSdkRemote).
 			Call(func() error { return gitutil.New(jirix.NewSeq()).Reset(m.spec.sdkVersion) }, "git reset --hard %s", m.spec.sdkVersion).
 			Popd()
 
@@ -448,51 +475,56 @@
 			Popd()
 
 		servicesSrc := filepath.Join(tmpMojoCheckout, "mojo", "services")
-		servicesDst := filepath.Join(outDir, "src", "mojo", "services")
-		seq.Rename(servicesSrc, servicesDst)
+		servicesDir := filepath.Join(srcDir, "mojo", "services")
+		seq.Rename(servicesSrc, servicesDir)
 
-		// Find all .mojom files.
-		var mojomFilesBuffer bytes.Buffer
-		if err := jirix.NewSeq().Capture(&mojomFilesBuffer, nil).Last("find", outDir, "-name", "*.mojom"); err != nil {
-			return err
+		// Generate mojom bindings.
+		seq.Pushd(srcDir)
+
+		// Fetch the mojom compiler.
+		bindingsDir := filepath.Join(publicDir, "tools", "bindings")
+		compilerDir := filepath.Join(bindingsDir, "mojom_tool", "bin")
+		compilerName := "mojom"
+		if _, err := os.Stat(compilerDir); os.IsNotExist(err) {
+			// For an old versions < 8.
+			compilerDir = filepath.Join(bindingsDir, "mojom_parser", "bin")
+			compilerName = "mojom_parser"
 		}
-		mojomFiles := strings.Split(mojomFilesBuffer.String(), "\n")
-
-		// Generate the mojom.go files from all mojom files.
-		seq.Pushd(filepath.Join(outDir, "src"))
-		// Fetch the mojom compiler
-		compilerDir := filepath.Join(outDir, "src", "mojo", "public", "tools", "bindings", "mojom_parser", "bin")
-
 		fetchCompiler := func(arch string) error {
-			hash, err := ioutil.ReadFile(filepath.Join(compilerDir, arch, "mojom_parser.sha1"))
+			hash, err := ioutil.ReadFile(filepath.Join(compilerDir, arch, compilerName+".sha1"))
 			if err != nil {
 				return err
 			}
 			binary := mojoCompilerUrl(arch, string(hash))
-			return profilesutil.Fetch(jirix, filepath.Join(compilerDir, arch, "mojom_parser"), binary)
+			return profilesutil.Fetch(jirix, filepath.Join(compilerDir, arch, compilerName), binary)
 		}
 		seq.
 			Call(func() error { return fetchCompiler("linux64") }, "fetch linux64 mojom compiler").
-			Chmod(filepath.Join(compilerDir, "linux64", "mojom_parser"), 0755).
+			Chmod(filepath.Join(compilerDir, "linux64", compilerName), 0755).
 			Call(func() error { return fetchCompiler("mac64") }, "fetch mac64 mojom compiler").
-			Chmod(filepath.Join(compilerDir, "mac64", "mojom_parser"), 0755)
-		genMojomTool := filepath.Join(outDir, "src", "mojo", "public", "tools", "bindings", "mojom_bindings_generator.py")
+			Chmod(filepath.Join(compilerDir, "mac64", compilerName), 0755)
+
+		// Find all .mojom files excluding ones for testing.
+		var mojomFilesBuffer bytes.Buffer
+		if err := jirix.NewSeq().Capture(&mojomFilesBuffer, nil).Last("find", srcDir, "-name", "*.mojom"); err != nil {
+			return err
+		}
+		mojomFiles := strings.Split(strings.TrimSpace(mojomFilesBuffer.String()), "\n")
+
+		genDir := filepath.Join(outDir, "gen")
+		genMojomTool := filepath.Join(bindingsDir, "mojom_bindings_generator.py")
 		for _, mojomFile := range mojomFiles {
-			trimmedFile := strings.TrimSpace(mojomFile)
-			if trimmedFile == "" {
-				continue
-			}
 			seq.Run(genMojomTool,
 				"--use_bundled_pylibs",
-				"-g", "go",
-				"-o", filepath.Join("..", "gen"),
-				"-I", ".",
-				"-I", servicesDst,
 				"--generate-type-info",
-				trimmedFile)
+				"--no-gen-imports",
+				"-d", ".",
+				"-I", servicesDir,
+				"-g", "go,java",
+				"-o", genDir,
+				mojomFile)
 		}
 		seq.Popd()
-
 		return seq.Done()
 	}
 
diff --git a/madb/clear_data.go b/madb/clear_data.go
new file mode 100644
index 0000000..d058afb
--- /dev/null
+++ b/madb/clear_data.go
@@ -0,0 +1,62 @@
+// Copyright 2015 The Vanadium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+	"fmt"
+
+	"v.io/x/lib/cmdline"
+	"v.io/x/lib/gosh"
+)
+
+func init() {
+	initializeIDCacheFlags(&cmdMadbClearData.Flags)
+}
+
+var cmdMadbClearData = &cmdline.Command{
+	Runner: subCommandRunner{initMadbClearData, runMadbClearDataForDevice},
+	Name:   "clear-data",
+	Short:  "Clear your app data from all devices",
+	Long: `
+Clears your app data from all devices.
+
+`,
+	ArgsName: "[<application_id>]",
+	ArgsLong: `
+<application_id> is usually the package name where the activities are defined.
+(See: http://tools.android.com/tech-docs/new-build-system/applicationid-vs-packagename)
+
+
+If the application ID is not specified, madb automatically determines which app to be cleared, based
+on the build scripts found in the current working directory.
+
+If the working directory contains a Gradle Android project (i.e., has "build.gradle"), run a small
+Gradle script to extract the application ID.  In this case, the extracted ID is cached, so that
+"madb clear-data" can be repeated without even running the Gradle script again.  The ID can be
+re-extracted by clearing the cache by providing "-clear-cache" flag.
+`,
+}
+
+func initMadbClearData(env *cmdline.Env, args []string) ([]string, error) {
+	return initMadbCommand(env, args, false, false)
+}
+
+func runMadbClearDataForDevice(env *cmdline.Env, args []string, d device) error {
+	sh := gosh.NewShell(nil)
+	defer sh.Cleanup()
+
+	sh.ContinueOnError = true
+
+	if len(args) == 1 {
+		appID := args[0]
+
+		// TODO(youngseokyoon): maybe do something equivalent for flutter?
+		cmdArgs := []string{"-s", d.Serial, "shell", "pm", "clear", appID}
+		cmd := sh.Cmd("adb", cmdArgs...)
+		return runGoshCommandForDevice(cmd, d)
+	}
+
+	return fmt.Errorf("No arguments are provided and failed to extract the id from the build scripts.")
+}
diff --git a/madb/doc.go b/madb/doc.go
index 581ab07..21df511 100644
--- a/madb/doc.go
+++ b/madb/doc.go
@@ -15,12 +15,13 @@
    madb [flags] <command>
 
 The madb commands are:
+   clear-data  Clear your app data from all devices
    exec        Run the provided adb command on all devices and emulators
                concurrently
+   name        Manage device nicknames
    start       Launch your app on all devices
    stop        Stop your app on all devices
    uninstall   Uninstall your app from all devices
-   name        Manage device nicknames
    help        Display help for commands or topics
 
 The madb flags are:
@@ -29,8 +30,10 @@
  -e=false
    Restrict the command to only run on emulators.
  -n=
-   Comma-separated device serials, qualifiers, or nicknames (set by 'madb
-   name').  Command will be run only on specified devices.
+   Comma-separated device serials, qualifiers, device indices (e.g., '@1',
+   '@2'), or nicknames (set by 'madb name').  A device index is specified by an
+   '@' sign followed by the index of the device in the output of 'adb devices'
+   command, starting from 1.  Command will be run only on specified devices.
 
 The global flags are:
  -metadata=<just specify -metadata to activate>
@@ -38,6 +41,50 @@
  -time=false
    Dump timing information to stderr before exiting the program.
 
+Madb clear-data - Clear your app data from all devices
+
+Clears your app data from all devices.
+
+Usage:
+   madb clear-data [flags] [<application_id>]
+
+<application_id> is usually the package name where the activities are defined.
+(See:
+http://tools.android.com/tech-docs/new-build-system/applicationid-vs-packagename)
+
+If the application ID is not specified, madb automatically determines which app
+to be cleared, based on the build scripts found in the current working
+directory.
+
+If the working directory contains a Gradle Android project (i.e., has
+"build.gradle"), run a small Gradle script to extract the application ID.  In
+this case, the extracted ID is cached, so that "madb clear-data" can be repeated
+without even running the Gradle script again.  The ID can be re-extracted by
+clearing the cache by providing "-clear-cache" flag.
+
+The madb clear-data flags are:
+ -clear-cache=false
+   Clear the cache and re-extract the application ID and the main activity name.
+   Only takes effect when no arguments are provided.
+ -module=
+   Specify which application module to use, when the current directory is the
+   top level Gradle project containing multiple sub-modules.  When not
+   specified, the first available application module is used.  Only takes effect
+   when no arguments are provided.
+ -variant=
+   Specify which build variant to use.  When not specified, the first available
+   build variant is used.  Only takes effect when no arguments are provided.
+
+ -d=false
+   Restrict the command to only run on real devices.
+ -e=false
+   Restrict the command to only run on emulators.
+ -n=
+   Comma-separated device serials, qualifiers, device indices (e.g., '@1',
+   '@2'), or nicknames (set by 'madb name').  A device index is specified by an
+   '@' sign followed by the index of the device in the output of 'adb devices'
+   command, starting from 1.  Command will be run only on specified devices.
+
 Madb exec - Run the provided adb command on all devices and emulators concurrently
 
 Runs the provided adb command on all devices and emulators concurrently.
@@ -63,8 +110,140 @@
  -e=false
    Restrict the command to only run on emulators.
  -n=
-   Comma-separated device serials, qualifiers, or nicknames (set by 'madb
-   name').  Command will be run only on specified devices.
+   Comma-separated device serials, qualifiers, device indices (e.g., '@1',
+   '@2'), or nicknames (set by 'madb name').  A device index is specified by an
+   '@' sign followed by the index of the device in the output of 'adb devices'
+   command, starting from 1.  Command will be run only on specified devices.
+
+Madb name - Manage device nicknames
+
+Manages device nicknames, which are meant to be more human-friendly compared to
+the device serials provided by adb tool.
+
+NOTE: Device specifier flags (-d, -e, -n) are ignored in all 'madb name'
+commands.
+
+Usage:
+   madb name [flags] <command>
+
+The madb name commands are:
+   set         Set a nickname to be used in place of the device serial.
+   unset       Unset a nickname set by the 'madb name set' command.
+   list        List all the existing nicknames.
+   clear-all   Clear all the existing nicknames.
+
+The madb name flags are:
+ -d=false
+   Restrict the command to only run on real devices.
+ -e=false
+   Restrict the command to only run on emulators.
+ -n=
+   Comma-separated device serials, qualifiers, device indices (e.g., '@1',
+   '@2'), or nicknames (set by 'madb name').  A device index is specified by an
+   '@' sign followed by the index of the device in the output of 'adb devices'
+   command, starting from 1.  Command will be run only on specified devices.
+
+Madb name set
+
+Sets a human-friendly nickname that can be used when specifying the device in
+any madb commands.
+
+The device serial can be obtain using the 'adb devices -l' command. For example,
+consider the following example output:
+
+    HT4BVWV00023           device usb:3-3.4.2 product:volantisg model:Nexus_9 device:flounder_lte
+
+The first value, 'HT4BVWV00023', is the device serial. To assign a nickname for
+this device, run the following command:
+
+    madb name set HT4BVWV00023 MyTablet
+
+and it will assign the 'MyTablet' nickname to the device serial 'HT4BVWV00023'.
+The alternative device specifiers (e.g., 'usb:3-3.4.2', 'product:volantisg') can
+also have nicknames.
+
+When a nickname is set for a device serial, the nickname can be used to specify
+the device within madb commands.
+
+There can only be one nickname for a device serial. When the 'madb name set'
+command is invoked with a device serial with an already assigned nickname, the
+old one will be replaced with the newly provided one.
+
+Usage:
+   madb name set [flags] <device_serial> <nickname>
+
+<device_serial> is a device serial (e.g., 'HT4BVWV00023') or an alternative
+device specifier (e.g., 'usb:3-3.4.2') obtained from 'adb devices -l' command
+<nickname> is an alpha-numeric string with no special characters or spaces.
+
+The madb name set flags are:
+ -d=false
+   Restrict the command to only run on real devices.
+ -e=false
+   Restrict the command to only run on emulators.
+ -n=
+   Comma-separated device serials, qualifiers, device indices (e.g., '@1',
+   '@2'), or nicknames (set by 'madb name').  A device index is specified by an
+   '@' sign followed by the index of the device in the output of 'adb devices'
+   command, starting from 1.  Command will be run only on specified devices.
+
+Madb name unset
+
+Unsets a nickname assigned by the 'madb name set' command. Either the device
+serial or the assigned nickname can be specified to remove the mapping.
+
+Usage:
+   madb name unset [flags] <device_serial | nickname>
+
+There should be only one argument, which is either the device serial or the
+nickname.
+
+The madb name unset flags are:
+ -d=false
+   Restrict the command to only run on real devices.
+ -e=false
+   Restrict the command to only run on emulators.
+ -n=
+   Comma-separated device serials, qualifiers, device indices (e.g., '@1',
+   '@2'), or nicknames (set by 'madb name').  A device index is specified by an
+   '@' sign followed by the index of the device in the output of 'adb devices'
+   command, starting from 1.  Command will be run only on specified devices.
+
+Madb name list
+
+Lists all the currently stored nicknames of device serials.
+
+Usage:
+   madb name list [flags]
+
+The madb name list flags are:
+ -d=false
+   Restrict the command to only run on real devices.
+ -e=false
+   Restrict the command to only run on emulators.
+ -n=
+   Comma-separated device serials, qualifiers, device indices (e.g., '@1',
+   '@2'), or nicknames (set by 'madb name').  A device index is specified by an
+   '@' sign followed by the index of the device in the output of 'adb devices'
+   command, starting from 1.  Command will be run only on specified devices.
+
+Madb name clear-all
+
+Clears all the currently stored nicknames of device serials.
+
+Usage:
+   madb name clear-all [flags]
+
+The madb name clear-all flags are:
+ -d=false
+   Restrict the command to only run on real devices.
+ -e=false
+   Restrict the command to only run on emulators.
+ -n=
+   Comma-separated device serials, qualifiers, device indices (e.g., '@1',
+   '@2'), or nicknames (set by 'madb name').  A device index is specified by an
+   '@' sign followed by the index of the device in the output of 'adb devices'
+   command, starting from 1.  Command will be run only on specified devices.
 
 Madb start - Launch your app on all devices
 
@@ -119,8 +298,10 @@
  -e=false
    Restrict the command to only run on emulators.
  -n=
-   Comma-separated device serials, qualifiers, or nicknames (set by 'madb
-   name').  Command will be run only on specified devices.
+   Comma-separated device serials, qualifiers, device indices (e.g., '@1',
+   '@2'), or nicknames (set by 'madb name').  A device index is specified by an
+   '@' sign followed by the index of the device in the output of 'adb devices'
+   command, starting from 1.  Command will be run only on specified devices.
 
 Madb stop - Stop your app on all devices
 
@@ -164,8 +345,10 @@
  -e=false
    Restrict the command to only run on emulators.
  -n=
-   Comma-separated device serials, qualifiers, or nicknames (set by 'madb
-   name').  Command will be run only on specified devices.
+   Comma-separated device serials, qualifiers, device indices (e.g., '@1',
+   '@2'), or nicknames (set by 'madb name').  A device index is specified by an
+   '@' sign followed by the index of the device in the output of 'adb devices'
+   command, starting from 1.  Command will be run only on specified devices.
 
 Madb uninstall - Uninstall your app from all devices
 
@@ -208,125 +391,10 @@
  -e=false
    Restrict the command to only run on emulators.
  -n=
-   Comma-separated device serials, qualifiers, or nicknames (set by 'madb
-   name').  Command will be run only on specified devices.
-
-Madb name - Manage device nicknames
-
-Manages device nicknames, which are meant to be more human-friendly compared to
-the device serials provided by adb tool.
-
-Usage:
-   madb name [flags] <command>
-
-The madb name commands are:
-   set         Set a nickname to be used in place of the device serial.
-   unset       Unset a nickname set by the 'madb name set' command.
-   list        List all the existing nicknames.
-   clear-all   Clear all the existing nicknames.
-
-The madb name flags are:
- -d=false
-   Restrict the command to only run on real devices.
- -e=false
-   Restrict the command to only run on emulators.
- -n=
-   Comma-separated device serials, qualifiers, or nicknames (set by 'madb
-   name').  Command will be run only on specified devices.
-
-Madb name set
-
-Sets a human-friendly nickname that can be used when specifying the device in
-any madb commands.
-
-The device serial can be obtain using the 'adb devices -l' command. For example,
-consider the following example output:
-
-    HT4BVWV00023           device usb:3-3.4.2 product:volantisg model:Nexus_9 device:flounder_lte
-
-The first value, 'HT4BVWV00023', is the device serial. To assign a nickname for
-this device, run the following command:
-
-    madb name set HT4BVWV00023 MyTablet
-
-and it will assign the 'MyTablet' nickname to the device serial 'HT4BVWV00023'.
-The alternative device specifiers (e.g., 'usb:3-3.4.2', 'product:volantisg') can
-also have nicknames.
-
-When a nickname is set for a device serial, the nickname can be used to specify
-the device within madb commands.
-
-There can only be one nickname for a device serial. When the 'madb name set'
-command is invoked with a device serial with an already assigned nickname, the
-old one will be replaced with the newly provided one.
-
-Usage:
-   madb name set [flags] <device_serial> <nickname>
-
-<device_serial> is a device serial (e.g., 'HT4BVWV00023') or an alternative
-device specifier (e.g., 'usb:3-3.4.2') obtained from 'adb devices -l' command
-<nickname> is an alpha-numeric string with no special characters or spaces.
-
-The madb name set flags are:
- -d=false
-   Restrict the command to only run on real devices.
- -e=false
-   Restrict the command to only run on emulators.
- -n=
-   Comma-separated device serials, qualifiers, or nicknames (set by 'madb
-   name').  Command will be run only on specified devices.
-
-Madb name unset
-
-Unsets a nickname assigned by the 'madb name set' command. Either the device
-serial or the assigned nickname can be specified to remove the mapping.
-
-Usage:
-   madb name unset [flags] <device_serial | nickname>
-
-There should be only one argument, which is either the device serial or the
-nickname.
-
-The madb name unset flags are:
- -d=false
-   Restrict the command to only run on real devices.
- -e=false
-   Restrict the command to only run on emulators.
- -n=
-   Comma-separated device serials, qualifiers, or nicknames (set by 'madb
-   name').  Command will be run only on specified devices.
-
-Madb name list
-
-Lists all the currently stored nicknames of device serials.
-
-Usage:
-   madb name list [flags]
-
-The madb name list flags are:
- -d=false
-   Restrict the command to only run on real devices.
- -e=false
-   Restrict the command to only run on emulators.
- -n=
-   Comma-separated device serials, qualifiers, or nicknames (set by 'madb
-   name').  Command will be run only on specified devices.
-
-Madb name clear-all
-
-Clears all the currently stored nicknames of device serials.
-
-Usage:
-   madb name clear-all [flags]
-
-The madb name clear-all flags are:
- -d=false
-   Restrict the command to only run on real devices.
- -e=false
-   Restrict the command to only run on emulators.
- -n=
-   Comma-separated device serials, qualifiers, or nicknames (set by 'madb
-   name').  Command will be run only on specified devices.
+   Comma-separated device serials, qualifiers, device indices (e.g., '@1',
+   '@2'), or nicknames (set by 'madb name').  A device index is specified by an
+   '@' sign followed by the index of the device in the output of 'adb devices'
+   command, starting from 1.  Command will be run only on specified devices.
 
 Madb help - Display help for commands or topics
 
diff --git a/madb/madb.go b/madb/madb.go
index 92c2db9..7078841 100644
--- a/madb/madb.go
+++ b/madb/madb.go
@@ -16,6 +16,7 @@
 	"os/exec"
 	"path"
 	"path/filepath"
+	"strconv"
 	"strings"
 	"sync"
 
@@ -39,7 +40,7 @@
 func init() {
 	cmdMadb.Flags.BoolVar(&allDevicesFlag, "d", false, `Restrict the command to only run on real devices.`)
 	cmdMadb.Flags.BoolVar(&allEmulatorsFlag, "e", false, `Restrict the command to only run on emulators.`)
-	cmdMadb.Flags.StringVar(&devicesFlag, "n", "", `Comma-separated device serials, qualifiers, or nicknames (set by 'madb name').  Command will be run only on specified devices.`)
+	cmdMadb.Flags.StringVar(&devicesFlag, "n", "", `Comma-separated device serials, qualifiers, device indices (e.g., '@1', '@2'), or nicknames (set by 'madb name').  A device index is specified by an '@' sign followed by the index of the device in the output of 'adb devices' command, starting from 1.  Command will be run only on specified devices.`)
 
 	// Store the current working directory.
 	var err error
@@ -57,7 +58,7 @@
 }
 
 var cmdMadb = &cmdline.Command{
-	Children: []*cmdline.Command{cmdMadbExec, cmdMadbStart, cmdMadbStop, cmdMadbUninstall, cmdMadbName},
+	Children: []*cmdline.Command{cmdMadbClearData, cmdMadbExec, cmdMadbName, cmdMadbStart, cmdMadbStop, cmdMadbUninstall},
 	Name:     "madb",
 	Short:    "Multi-device Android Debug Bridge",
 	Long: `
@@ -95,6 +96,7 @@
 	Type       deviceType
 	Qualifiers []string
 	Nickname   string
+	Index      int
 }
 
 // Returns the display name which is intended to be used as the console output prefix.
@@ -116,7 +118,7 @@
 
 	nsm, err := readNicknameSerialMap(nicknameFile)
 	if err != nil {
-		fmt.Fprintln(os.Stderr, "Warning: Could not read the nickname file.")
+		return nil, err
 	}
 
 	return parseDevicesOutput(output, nsm)
@@ -135,17 +137,18 @@
 	}
 
 	// Iterate over all the device serial numbers, starting from the second line.
-	for _, line := range lines[1:] {
+	for i, line := range lines[1:] {
 		fields := strings.Fields(line)
 
 		if len(fields) <= 1 || fields[1] == "offline" {
 			continue
 		}
 
-		// Fill in the device serial and all the qualifiers.
+		// Fill in the device serial, all the qualifiers, and the device index.
 		d := device{
 			Serial:     fields[0],
 			Qualifiers: fields[2:],
+			Index:      i + 1,
 		}
 
 		// Determine whether this device is an emulator or a real device.
@@ -191,7 +194,10 @@
 		return nil, err
 	}
 
-	filtered := filterSpecifiedDevices(allDevices)
+	filtered, err := filterSpecifiedDevices(allDevices)
+	if err != nil {
+		return nil, err
+	}
 
 	if len(filtered) == 0 {
 		return nil, fmt.Errorf("No devices matching the device specifiers.")
@@ -200,21 +206,42 @@
 	return filtered, nil
 }
 
-func filterSpecifiedDevices(devices []device) []device {
+type deviceSpec struct {
+	index int
+	token string
+}
+
+func filterSpecifiedDevices(devices []device) ([]device, error) {
 	// If no device specifier flags are set, run on all devices and emulators.
 	if noDevicesSpecified() {
-		return devices
+		return devices, nil
 	}
 
 	result := make([]device, 0, len(devices))
 
+	var specs = []deviceSpec{}
+	if devicesFlag != "" {
+		tokens := strings.Split(devicesFlag, ",")
+		for _, token := range tokens {
+			if strings.HasPrefix(token, "@") {
+				index, err := strconv.Atoi(token[1:])
+				if err != nil || index <= 0 {
+					return nil, fmt.Errorf("Invalid device specifier %q. '@' sign must be followed by a numeric device index starting from 1.", token)
+				}
+				specs = append(specs, deviceSpec{index, ""})
+			} else {
+				specs = append(specs, deviceSpec{0, token})
+			}
+		}
+	}
+
 	for _, d := range devices {
-		if shouldIncludeDevice(d) {
+		if shouldIncludeDevice(d, specs) {
 			result = append(result, d)
 		}
 	}
 
-	return result
+	return result, nil
 }
 
 func noDevicesSpecified() bool {
@@ -223,7 +250,7 @@
 		devicesFlag == ""
 }
 
-func shouldIncludeDevice(d device) bool {
+func shouldIncludeDevice(d device, specs []deviceSpec) bool {
 	if allDevicesFlag && d.Type == realDevice {
 		return true
 	}
@@ -232,19 +259,25 @@
 		return true
 	}
 
-	tokens := strings.Split(devicesFlag, ",")
-	for _, token := range tokens {
+	for _, spec := range specs {
 		// Ignore empty tokens
-		if token == "" {
+		if spec.index == 0 && spec.token == "" {
 			continue
 		}
 
-		if d.Serial == token || d.Nickname == token {
+		if spec.index > 0 {
+			if d.Index == spec.index {
+				return true
+			}
+			continue
+		}
+
+		if d.Serial == spec.token || d.Nickname == spec.token {
 			return true
 		}
 
 		for _, qualifier := range d.Qualifiers {
-			if qualifier == token {
+			if qualifier == spec.token {
 				return true
 			}
 		}
diff --git a/madb/madb_test.go b/madb/madb_test.go
index 261c592..6c4ec79 100644
--- a/madb/madb_test.go
+++ b/madb/madb_test.go
@@ -43,12 +43,14 @@
 			Type:       realDevice,
 			Qualifiers: []string{"usb:3-3.4.3", "product:bullhead", "model:Nexus_5X", "device:bullhead"},
 			Nickname:   "",
+			Index:      1,
 		},
 		device{
 			Serial:     "emulator-5554",
 			Type:       emulator,
 			Qualifiers: []string{"product:sdk_phone_armv7", "model:sdk_phone_armv7", "device:generic"},
 			Nickname:   "",
+			Index:      2,
 		},
 	}
 
@@ -86,6 +88,7 @@
 			Type:       realDevice,
 			Qualifiers: []string{"product:sdk_phone_armv7", "model:sdk_phone_armv7", "device:generic"},
 			Nickname:   "",
+			Index:      2,
 		},
 	}
 
@@ -116,12 +119,14 @@
 			Type:       realDevice,
 			Qualifiers: []string{"usb:3-3.4.3", "product:bullhead", "model:Nexus_5X", "device:bullhead"},
 			Nickname:   "MyPhone",
+			Index:      1,
 		},
 		device{
 			Serial:     "emulator-5554",
 			Type:       emulator,
 			Qualifiers: []string{"product:sdk_phone_armv7", "model:sdk_phone_armv7", "device:generic"},
 			Nickname:   "ARMv7",
+			Index:      2,
 		},
 	}
 
@@ -137,6 +142,7 @@
 		Type:       realDevice,
 		Qualifiers: []string{"usb:3-3.4.3", "product:bullhead", "model:Nexus_5X", "device:bullhead"},
 		Nickname:   "MyPhone",
+		Index:      1,
 	}
 
 	d2 := device{
@@ -144,6 +150,7 @@
 		Type:       realDevice,
 		Qualifiers: []string{"usb:3-3.4.1", "product:volantisg", "model:Nexus_9", "device:flounder_lte"},
 		Nickname:   "",
+		Index:      2,
 	}
 
 	e1 := device{
@@ -151,6 +158,7 @@
 		Type:       emulator,
 		Qualifiers: []string{"product:sdk_phone_armv7", "model:sdk_phone_armv7", "device:generic"},
 		Nickname:   "ARMv7",
+		Index:      3,
 	}
 
 	d3 := device{
@@ -158,6 +166,7 @@
 		Type:       realDevice,
 		Qualifiers: []string{"usb:3-3.3", "product:bullhead", "model:Nexus_5X", "device:bullhead"},
 		Nickname:   "SecondPhone",
+		Index:      4,
 	}
 
 	e2 := device{
@@ -165,6 +174,7 @@
 		Type:       emulator,
 		Qualifiers: []string{"product:sdk_phone_armv7", "model:sdk_phone_armv7", "device:generic"},
 		Nickname:   "",
+		Index:      5,
 	}
 
 	allDevices := []device{d1, d2, e1, d3, e2}
@@ -185,8 +195,10 @@
 		{deviceFlags{false, true, ""}, []device{e1, e2}},                   // Only -e is specified
 		{deviceFlags{false, false, "device:bullhead"}, []device{d1, d3}},   // Device qualifier
 		{deviceFlags{false, false, "ARMv7,SecondPhone"}, []device{e1, d3}}, // Nicknames
+		{deviceFlags{false, false, "@2,@4"}, []device{d2, d3}},             // Device Indices
 		{deviceFlags{true, false, "ARMv7"}, []device{d1, d2, e1, d3}},      // Combinations
 		{deviceFlags{false, true, "model:Nexus_9"}, []device{d2, e1, e2}},  // Combinations
+		{deviceFlags{false, false, "@1,SecondPhone"}, []device{d1, d3}},    // Combinations
 	}
 
 	for i, testCase := range testCases {
@@ -194,7 +206,12 @@
 		allEmulatorsFlag = testCase.flags.allEmulators
 		devicesFlag = testCase.flags.devices
 
-		if got := filterSpecifiedDevices(allDevices); !reflect.DeepEqual(got, testCase.want) {
+		got, err := filterSpecifiedDevices(allDevices)
+		if err != nil {
+			t.Fatalf(err.Error())
+		}
+
+		if !reflect.DeepEqual(got, testCase.want) {
 			t.Fatalf("unmatched results for testCases[%v]: got %v, want %v", i, got, testCase.want)
 		}
 	}
diff --git a/madb/name.go b/madb/name.go
index 8b2542d..b5fc2b4 100644
--- a/madb/name.go
+++ b/madb/name.go
@@ -5,12 +5,11 @@
 package main
 
 import (
-	"bufio"
+	"encoding/json"
 	"fmt"
 	"os"
 	"path/filepath"
 	"regexp"
-	"strings"
 
 	"v.io/x/lib/cmdline"
 )
@@ -22,6 +21,8 @@
 	Long: `
 Manages device nicknames, which are meant to be more human-friendly compared to
 the device serials provided by adb tool.
+
+NOTE: Device specifier flags (-d, -e, -n) are ignored in all 'madb name' commands.
 `,
 }
 
@@ -224,20 +225,26 @@
 
 	f, err := os.Open(filename)
 	if err != nil {
+		// Nickname file may not exist when there are no nicknames assigned, and it is not an error.
+		if os.IsNotExist(err) {
+			return result, nil
+		}
+
 		return nil, err
 	}
 	defer f.Close()
 
-	// TODO(youngseokyoon): use encoding/json for serialization and deserialization.
-	scanner := bufio.NewScanner(f)
-	for scanner.Scan() {
-		line := scanner.Text()
-		fields := strings.Fields(line)
-		if len(fields) == 2 {
-			result[fields[0]] = fields[1]
-		} else {
-			return nil, fmt.Errorf("Unexpected number of columns in the nickname file.")
+	decoder := json.NewDecoder(f)
+
+	// Decoding might fail when the nickname file is somehow corrupted, or when the schema is updated.
+	// In such cases, move on after resetting the cache file instead of exiting the app.
+	if err := decoder.Decode(&result); err != nil {
+		fmt.Fprintf(os.Stderr, "WARNING: Could not decode the nickname file: %q.  Resetting the file.\n", err)
+		if err := os.Remove(f.Name()); err != nil {
+			return nil, err
 		}
+
+		return make(map[string]string), nil
 	}
 
 	return result, nil
@@ -252,11 +259,8 @@
 	}
 	defer f.Close()
 
-	for nickname, serial := range nsm {
-		fmt.Fprintln(f, nickname, serial)
-	}
-
-	return nil
+	encoder := json.NewEncoder(f)
+	return encoder.Encode(nsm)
 }
 
 // runnerFuncWithFilepath is an adapter that turns the madb name subcommand functions into cmdline.Runners.
diff --git a/madb/name_test.go b/madb/name_test.go
index 31480f2..9a39c27 100644
--- a/madb/name_test.go
+++ b/madb/name_test.go
@@ -5,7 +5,6 @@
 package main
 
 import (
-	"fmt"
 	"os"
 	"reflect"
 	"testing"
@@ -177,55 +176,3 @@
 		}
 	}
 }
-
-func TestReadNicknameSerialMap(t *testing.T) {
-	filename := tempFilename(t)
-	defer os.Remove(filename)
-
-	f, err := os.Create(filename)
-	if err != nil {
-		t.Fatal(err)
-	}
-	fmt.Fprintln(f, "PHONE1 SERIAL1")
-	fmt.Fprintln(f, "PHONE2 SERIAL2")
-	fmt.Fprintln(f, "PHONE3 SERIAL3")
-	f.Close()
-
-	var got map[string]string
-	if got, err = readNicknameSerialMap(filename); err != nil {
-		t.Fatal(err)
-	}
-	want := map[string]string{
-		"PHONE1": "SERIAL1",
-		"PHONE2": "SERIAL2",
-		"PHONE3": "SERIAL3",
-	}
-
-	if !reflect.DeepEqual(got, want) {
-		t.Fatalf("unmatched results: got %v, want %v", got, want)
-	}
-}
-
-func TestWriteNicknameSerialMap(t *testing.T) {
-	filename := tempFilename(t)
-	defer os.Remove(filename)
-
-	want := map[string]string{
-		"PHONE1": "SERIAL1",
-		"PHONE2": "SERIAL2",
-		"PHONE3": "SERIAL3",
-	}
-
-	if err := writeNicknameSerialMap(want, filename); err != nil {
-		t.Fatalf("could not write the map to file: %v", err)
-	}
-
-	got, err := readNicknameSerialMap(filename)
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	if !reflect.DeepEqual(got, want) {
-		t.Fatalf("unmatched results: got %v, want %v", got, want)
-	}
-}
diff --git a/tracify/doc.go b/tracify/doc.go
new file mode 100644
index 0000000..281d163
--- /dev/null
+++ b/tracify/doc.go
@@ -0,0 +1,26 @@
+// Copyright 2015 The Vanadium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file was auto-generated via go generate.
+// DO NOT UPDATE MANUALLY
+
+/*
+tracify adds vtrace annotations to all functions in the given packages that have
+a context as the first argument.
+
+TODO(mattr): We will eventually support various options like excluding certain
+functions or including specific information in the span name.
+
+Usage:
+   tracify [flags] [-t] [packages]
+
+The global flags are:
+ -metadata=<just specify -metadata to activate>
+   Displays metadata for the program and exits.
+ -t=false
+   include transitive dependencies of named packages.
+ -time=false
+   Dump timing information to stderr before exiting the program.
+*/
+package main
diff --git a/tracify/injector.go b/tracify/injector.go
new file mode 100644
index 0000000..21d0476
--- /dev/null
+++ b/tracify/injector.go
@@ -0,0 +1,72 @@
+// Copyright 2015 The Vanadium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+	"bytes"
+	"go/token"
+	"io"
+	"io/ioutil"
+	"os"
+	"text/template"
+)
+
+// injectors allow you to rewrite a file adding content at points specified in the source files
+// address space.
+type injector struct {
+	read  int
+	r     io.Reader
+	w     bytes.Buffer
+	fname string
+}
+
+func newInjector(fname string) (*injector, error) {
+	var err error
+	i := &injector{fname: fname}
+	i.r, err = os.Open(fname)
+	return i, err
+}
+
+func (i *injector) copyTo(p token.Position) error {
+	toread := p.Offset + 1 - i.read
+	i.read += toread
+	_, err := io.CopyN(&i.w, i.r, int64(toread))
+	return err
+}
+
+func (i *injector) inject(p token.Position, content string) error {
+	if err := i.copyTo(p); err != nil {
+		return err
+	}
+	_, err := i.w.Write([]byte(content))
+	return err
+}
+
+func (i *injector) format() error {
+	if _, err := io.Copy(&i.w, i.r); err != nil {
+		return err
+	}
+	//out, err := format.Source(i.w.Bytes())
+	//if err != nil {
+	//	return err
+	//}
+	out := i.w.Bytes()
+	f, err := os.Create(i.fname)
+	if err != nil {
+		return err
+	}
+	stat, err := f.Stat()
+	if err != nil {
+		return err
+	}
+	return ioutil.WriteFile(i.fname, out, stat.Mode())
+}
+
+func (i *injector) execute(p token.Position, t *template.Template, data interface{}) error {
+	if err := i.copyTo(p); err != nil {
+		return err
+	}
+	return t.Execute(&i.w, data)
+}
diff --git a/tracify/tracify.go b/tracify/tracify.go
new file mode 100644
index 0000000..84b72aa
--- /dev/null
+++ b/tracify/tracify.go
@@ -0,0 +1,314 @@
+// Copyright 2015 The Vanadium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// The following enables go generate to generate the doc.go file.
+//go:generate go run $JIRI_ROOT/release/go/src/v.io/x/lib/cmdline/testdata/gendoc.go . -help
+
+package main
+
+import (
+	"bytes"
+	"encoding/json"
+	"flag"
+	"fmt"
+	"go/ast"
+	"go/build"
+	"go/format"
+	"go/parser"
+	"go/token"
+	"io"
+	"os/exec"
+	"strings"
+
+	"text/template"
+	"v.io/x/lib/cmdline"
+	"v.io/x/lib/envvar"
+)
+
+var skipPackages = map[string]bool{
+	"v.io/v23/vtrace":                    true,
+	"v.io/v23/verror":                    true,
+	"v.io/x/ref/runtime/internal/vtrace": true,
+}
+
+func main() {
+	cmdline.Main(cmdTracify)
+}
+
+var (
+	transitive = flag.Bool("t", false, "include transitive dependencies of named packages.")
+)
+
+var cmdTracify = &cmdline.Command{
+	Name:  "tracify",
+	Short: "Add vtrace annotations to functions in the specified packages.",
+	Long: `
+tracify adds vtrace annotations to all functions in the given packages that
+have a context as the first argument.
+
+TODO(mattr): We will eventually support various options like excluding certain functions
+or including specific information in the span name.
+`,
+	ArgsName: "[-t] [packages]",
+	Runner:   cmdline.RunnerFunc(tracify),
+}
+
+// tracify adds vtrace spans to functions in the packages defined by args.
+func tracify(env *cmdline.Env, args []string) error {
+	pkgs, err := readPackages(env, args)
+	if err != nil {
+		return err
+	}
+	if *transitive {
+		tPkgs := map[string]*build.Package{}
+		for _, pkg := range pkgs {
+			if err := addTransitive(tPkgs, pkg, true); err != nil {
+				return err
+			}
+		}
+		pkgs = tPkgs
+	}
+	for _, pkg := range pkgs {
+		if pkg != nil {
+			if err := processPackage(pkg); err != nil {
+				return err
+			}
+		}
+	}
+	return nil
+}
+
+// processPackage processes a build package, rewriting any file in the package
+// to include vtrace annotations.
+func processPackage(pkg *build.Package) error {
+	fset := token.NewFileSet()
+	pkgs, err := parser.ParseDir(fset, pkg.Dir, nil, parser.ParseComments)
+	if err != nil {
+		return err
+	}
+	for _, p := range pkgs {
+		for fname, f := range p.Files {
+			processFile(fset, fname, f)
+		}
+	}
+	return nil
+}
+
+var vtraceTpl = template.Must(template.New("vtrace").Parse(`
+	{{.CtxName}}, vspan := {{.VtraceName}}.WithNewSpan({{.CtxName}}, "{{.FuncName}}")
+	defer vspan.Finish()
+`))
+
+type decl struct {
+	pos        token.Position
+	CtxName    string
+	FuncName   string
+	VtraceName string
+}
+
+// processFile Processes a single source file, rewriting it to include vtrace
+// spans where necessary.
+func processFile(fset *token.FileSet, fname string, f *ast.File) error {
+	vtraceName := ""
+	for _, i := range f.Imports {
+		if i.Path.Value == "\"v.io/v23/vtrace\"" {
+			if i.Name == nil {
+				vtraceName = "vtrace"
+			} else {
+				vtraceName = i.Name.Name
+			}
+		}
+	}
+
+	decls := []decl{}
+	args := translateTypes(fset, f.Imports, []string{"*context.T"})
+	for _, d := range f.Decls {
+		if fd, ok := d.(*ast.FuncDecl); ok {
+			matches, names := checkParams(fset, fd.Type, args)
+			if !matches || len(names) == 0 || names[0] == "_" {
+				continue
+			}
+			decls = append(decls, decl{
+				pos:      fset.Position(fd.Body.Lbrace),
+				CtxName:  names[0],
+				FuncName: fd.Name.Name,
+			})
+		}
+	}
+
+	if len(decls) > 0 {
+		inj, err := newInjector(fname)
+		if err != nil {
+			return err
+		}
+		if vtraceName == "" {
+			if err := inj.inject(fset.Position(f.Name.End()), "\nimport \"v.io/v23/vtrace\"\n"); err != nil {
+				return err
+			}
+			vtraceName = "vtrace"
+		}
+		for _, d := range decls {
+			d.VtraceName = vtraceName
+			if err := inj.execute(d.pos, vtraceTpl, d); err != nil {
+				return err
+			}
+		}
+		if err := inj.format(); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+// readPackages resolves the user-supplied package patterns to a list of actual packages.
+// We just call out to 'go list' for this since there is actually a lot of subtlety
+// in resolving the patterns.
+func readPackages(env *cmdline.Env, args []string) (map[string]*build.Package, error) {
+	buf := &bytes.Buffer{}
+	opts := []string{"list", "-json"}
+	cmd := exec.Command("go", append(opts, args...)...)
+	cmd.Env = envvar.MapToSlice(env.Vars)
+	cmd.Stderr = env.Stderr
+	cmd.Stdout = buf
+	if err := cmd.Run(); err != nil {
+		return nil, fmt.Errorf("Could not list packages: %v", err)
+	}
+	dec := json.NewDecoder(buf)
+	packages := map[string]*build.Package{}
+	for {
+		var pkg build.Package
+		if err := dec.Decode(&pkg); err == io.EOF {
+			break
+		} else if err != nil {
+			return nil, err
+		}
+		packages[pkg.ImportPath] = &pkg
+	}
+	return packages, nil
+}
+
+// addTransitive adds the transitive dependencies of pkg to packages.
+func addTransitive(packages map[string]*build.Package, pkg *build.Package, alsoTest bool) error {
+	if skipPackages[pkg.ImportPath] {
+		return nil
+	}
+	if _, ok := packages[pkg.ImportPath]; ok {
+		return nil
+	}
+	packages[pkg.ImportPath] = nil
+	foundCtx := false
+	for _, dep := range pkg.Imports {
+		if dep == "v.io/v23/context" {
+			foundCtx = true
+			break
+		}
+	}
+
+	allImports := [][]string{pkg.Imports}
+	if alsoTest {
+		allImports = append(allImports, pkg.TestImports, pkg.XTestImports)
+	}
+
+	for _, imports := range allImports {
+		for _, dep := range imports {
+			if dep == "C" {
+				continue
+			}
+			depPkg, err := build.Import(dep, "", 0)
+			if err != nil {
+				return err
+			}
+			if err := addTransitive(packages, depPkg, false); err != nil {
+				return err
+			}
+		}
+	}
+	// Skip if we don't depend on context.
+	if foundCtx {
+		packages[pkg.ImportPath] = pkg
+	}
+	return nil
+}
+
+// checkParams returns true if the given function type has argument types matching
+// the strings in args.
+func checkParams(fset *token.FileSet, ftype *ast.FuncType, args []string) (bool, []string) {
+	i := 0
+	names := []string{}
+	buf := &bytes.Buffer{}
+	for _, param := range ftype.Params.List {
+		buf.Reset()
+		format.Node(buf, fset, param.Type)
+		typeStr := buf.String()
+		nnames := len(param.Names)
+		if nnames == 0 {
+			nnames = 1 //Anonymous field.
+		}
+		for n := 0; n < nnames; n++ {
+			if args[i] != typeStr {
+				return false, nil
+			}
+			if n < len(param.Names) {
+				names = append(names, param.Names[n].Name)
+			}
+			if i++; i >= len(args) {
+				return true, names
+			}
+		}
+	}
+	return false, nil
+}
+
+// translateTypes uses the declared imports to change a list of queried types to their mapped versions.
+// For example if you call:
+//    translateTypes(fset, imports, "*testing.T")
+// and imports contains the import:
+//    import t "testing"
+// Then we will return:
+//    []string{"*t.T"}
+func translateTypes(fset *token.FileSet, imports []*ast.ImportSpec, types []string) []string {
+	namedImports := map[string]string{}
+	for _, i := range imports {
+		if i.Name != nil {
+			path := strings.Trim(i.Path.Value, "\"")
+			namedImports[path] = i.Name.Name
+		}
+	}
+	out := make([]string, len(types))
+	buf := &bytes.Buffer{}
+	for i, typ := range types {
+		out[i] = typ
+		if expr, err := parser.ParseExpr(typ); err == nil && changePackage(expr, namedImports) {
+			buf.Reset()
+			if err := format.Node(buf, fset, expr); err == nil {
+				out[i] = buf.String()
+			}
+		}
+	}
+	return out
+}
+
+// This changes the package name of a type to the mapped name.
+// For example if you pass in the expr corresponding to "*testing.T" but
+// the file has declared:
+//   import t "testing"
+// then it will return the expr for "*t.T".
+// TODO(mattr): I'm not sure this catches all the cases.  If we find a breakage
+// we can fix it then.
+func changePackage(expr ast.Expr, namedImports map[string]string) bool {
+	switch e := expr.(type) {
+	case *ast.StarExpr:
+		return changePackage(e.X, namedImports)
+	case *ast.SelectorExpr:
+		if id, ok := e.X.(*ast.Ident); ok {
+			if name, has := namedImports[id.Name]; has {
+				id.Name = name
+			}
+			return true
+		}
+		return false
+	default:
+		return false
+	}
+}