Snap for 6001391 from 10b111c8044faf0acf0be504fc630c921c758134 to qt-aml-networking-release

Change-Id: Ie397377e6ec9cb635f955a9048184e53556af97e
diff --git a/README.md b/README.md
index 9bd3fed..e9e9c06 100755
--- a/README.md
+++ b/README.md
@@ -105,6 +105,10 @@
 disk in a key:value format like so:
 `cpu:2,resolution:1280x700,dpi:160,memory:2g,disk:2g`
 
+* `--reuse-gce`: 'cuttlefish only' This can help users use their own instance.
+Reusing specific gce instance if `--reuse-gce` [instance-name] is provided.
+Select one gce instance to reuse if `--reuse-gce` is provided.
+
 The full list of options are available via `--help`
 
 > $ acloud create --help
diff --git a/create/local_image_local_instance.py b/create/local_image_local_instance.py
index 2b9f96e..25871ed 100644
--- a/create/local_image_local_instance.py
+++ b/create/local_image_local_instance.py
@@ -38,11 +38,9 @@
 import json
 import logging
 import os
-import re
 import shutil
 import subprocess
 import sys
-import tempfile
 
 from acloud import errors
 from acloud.create import base_avd_create
@@ -50,13 +48,13 @@
 from acloud.internal import constants
 from acloud.internal.lib import utils
 from acloud.internal.lib.adb_tools import AdbTools
+from acloud.list import list as list_instance
 from acloud.list import instance
 from acloud.public import report
 
 
 logger = logging.getLogger(__name__)
 
-_ACLOUD_CVD_TEMP = os.path.join(tempfile.gettempdir(), "acloud_cvd_temp")
 _CMD_LAUNCH_CVD_ARGS = (" -daemon -cpus %s -x_res %s -y_res %s -dpi %s "
                         "-memory_mb %s -system_image_dir %s "
                         "-instance_dir %s")
@@ -65,16 +63,12 @@
 _CONFIRM_RELAUNCH = ("\nCuttlefish AVD[id:%d] is already running. \n"
                      "Enter 'y' to terminate current instance and launch a new "
                      "instance, enter anything else to exit out[y/N]: ")
-_CVD_RUNTIME_FOLDER_NAME = "cuttlefish_runtime"
-_CVD_CONFIG_NAME = "cuttlefish_config.json"
 _ENV_ANDROID_HOST_OUT = "ANDROID_HOST_OUT"
 _ENV_CVD_HOME = "HOME"
 _ENV_CUTTLEFISH_INSTANCE = "CUTTLEFISH_INSTANCE"
 _LAUNCH_CVD_TIMEOUT_SECS = 60  # default timeout as 60 seconds
 _LAUNCH_CVD_TIMEOUT_ERROR = ("Cuttlefish AVD launch timeout, did not complete "
                              "within %d secs.")
-_LOCAL_INSTANCE_HOME = "instance_home_%s"
-_RE_LOCAL_CVD_PORT = re.compile(r"^127\.0\.0\.1:65(?P<cvd_port_suffix>\d{2})\s+")
 _VIRTUAL_DISK_PATHS = "virtual_disk_paths"
 
 
@@ -157,7 +151,8 @@
 
         return avd_spec.local_image_dir, host_bins_path
 
-    def PrepareLaunchCVDCmd(self, launch_cvd_path, hw_property, system_image_dir,
+    @staticmethod
+    def PrepareLaunchCVDCmd(launch_cvd_path, hw_property, system_image_dir,
                             local_instance_id):
         """Prepare launch_cvd command.
 
@@ -173,7 +168,7 @@
         Returns:
             String, launch_cvd cmd.
         """
-        instance_dir = self.GetLocalInstanceRuntimeDir(local_instance_id)
+        instance_dir = instance.GetLocalInstanceRuntimeDir(local_instance_id)
         launch_cvd_w_args = launch_cvd_path + _CMD_LAUNCH_CVD_ARGS % (
             hw_property["cpu"], hw_property["x_res"], hw_property["y_res"],
             hw_property["dpi"], hw_property["memory"], system_image_dir,
@@ -231,7 +226,8 @@
                                                    _LAUNCH_CVD_TIMEOUT_ERROR % timeout_secs)
         timeout_exception(self._LaunchCvd)(cmd, local_instance_id)
 
-    def _StopCvd(self, host_bins_path, local_instance_id):
+    @staticmethod
+    def _StopCvd(host_bins_path, local_instance_id):
         """Execute stop_cvd to stop cuttlefish instance.
 
         Args:
@@ -244,7 +240,7 @@
         with open(os.devnull, "w") as dev_null:
             cvd_env = os.environ.copy()
             cvd_env[constants.ENV_CUTTLEFISH_CONFIG_FILE] = os.path.join(
-                self.GetLocalInstanceRuntimeDir(local_instance_id),
+                instance.GetLocalInstanceRuntimeDir(local_instance_id),
                 constants.CUTTLEFISH_CONFIG_FILE)
             subprocess.check_call(
                 utils.AddUserGroupsToCmd(
@@ -260,8 +256,9 @@
         # sure adb device is completely gone since it will use the same adb port
         adb_cmd.DisconnectAdb(retry=True)
 
+    @staticmethod
     @utils.TimeExecute(function_description="Waiting for AVD(s) to boot up")
-    def _LaunchCvd(self, cmd, local_instance_id):
+    def _LaunchCvd(cmd, local_instance_id):
         """Execute Launch CVD.
 
         Kick off the launch_cvd command and log the output.
@@ -275,8 +272,8 @@
         """
         # Delete the cvd home/runtime temp if exist. The runtime folder is
         # under the cvd home dir, so we only delete them from home dir.
-        cvd_home_dir = self.GetLocalInstanceHomeDir(local_instance_id)
-        cvd_runtime_dir = self.GetLocalInstanceRuntimeDir(local_instance_id)
+        cvd_home_dir = instance.GetLocalInstanceHomeDir(local_instance_id)
+        cvd_runtime_dir = instance.GetLocalInstanceRuntimeDir(local_instance_id)
         shutil.rmtree(cvd_home_dir, ignore_errors=True)
         os.makedirs(cvd_runtime_dir)
 
@@ -303,31 +300,6 @@
             utils.TextColors.WARNING)
 
     @staticmethod
-    def GetLocalInstanceHomeDir(local_instance_id):
-        """Get instance home dir
-
-        Args:
-            local_instance_id: Integer of instance id.
-
-        Return:
-            String, path of instance home dir.
-        """
-        return os.path.join(_ACLOUD_CVD_TEMP,
-                            _LOCAL_INSTANCE_HOME % local_instance_id)
-
-    def GetLocalInstanceRuntimeDir(self, local_instance_id):
-        """Get instance runtime dir
-
-        Args:
-            local_instance_id: Integer of instance id.
-
-        Return:
-            String, path of instance runtime dir.
-        """
-        return os.path.join(self.GetLocalInstanceHomeDir(local_instance_id),
-                            _CVD_RUNTIME_FOLDER_NAME)
-
-    @staticmethod
     def IsLocalCVDRunning(local_instance_id):
         """Check if the AVD with specific instance id is running
 
@@ -340,7 +312,8 @@
         local_ports = instance.GetLocalPortsbyInsId(local_instance_id)
         return AdbTools(local_ports.adb_port).IsAdbConnected()
 
-    def IsLocalImageOccupied(self, local_image_dir):
+    @staticmethod
+    def IsLocalImageOccupied(local_image_dir):
         """Check if the given image path is being used by a running CVD process.
 
         Args:
@@ -349,10 +322,10 @@
         Return:
             Integer of instance id which using the same image path.
         """
-        local_cvd_ids = self._GetActiveCVDIds()
+        local_cvd_ids = list_instance.GetActiveCVDIds()
         for cvd_id in local_cvd_ids:
-            cvd_config_path = os.path.join(self.GetLocalInstanceRuntimeDir(
-                cvd_id), _CVD_CONFIG_NAME)
+            cvd_config_path = os.path.join(instance.GetLocalInstanceRuntimeDir(
+                cvd_id), constants.CUTTLEFISH_CONFIG_FILE)
             if not os.path.isfile(cvd_config_path):
                 continue
             with open(cvd_config_path, "r") as config_file:
@@ -361,24 +334,3 @@
                     if local_image_dir in disk_path:
                         return cvd_id
         return None
-
-    @staticmethod
-    def _GetActiveCVDIds():
-        """Get active cvd ids from adb devices.
-
-        The adb port of local instance will be decided according to instance id.
-        The rule of adb port will be '6520 + [instance id] - 1'. So we grep last
-        two digits of port and calculate the instance id.
-
-        Return:
-            List of cvd id.
-        """
-        local_cvd_ids = []
-        adb_cmd = [constants.ADB_BIN, "devices"]
-        device_info = subprocess.check_output(adb_cmd)
-        for device in device_info.splitlines():
-            match = _RE_LOCAL_CVD_PORT.match(device)
-            if match:
-                cvd_serial = match.group("cvd_port_suffix")
-                local_cvd_ids.append(int(cvd_serial) - 19)
-        return local_cvd_ids
diff --git a/create/local_image_local_instance_test.py b/create/local_image_local_instance_test.py
index fdc7618..1007739 100644
--- a/create/local_image_local_instance_test.py
+++ b/create/local_image_local_instance_test.py
@@ -19,6 +19,7 @@
 import mock
 
 from acloud.create import local_image_local_instance
+from acloud.list import instance
 from acloud.internal import constants
 from acloud.internal.lib import utils
 
@@ -41,8 +42,7 @@
         self.local_image_local_instance = local_image_local_instance.LocalImageLocalInstance()
 
     # pylint: disable=protected-access
-    @mock.patch.object(local_image_local_instance.LocalImageLocalInstance,
-                       "GetLocalInstanceRuntimeDir")
+    @mock.patch.object(instance, "GetLocalInstanceRuntimeDir")
     @mock.patch.object(utils, "CheckUserInGroups")
     def testPrepareLaunchCVDCmd(self, mock_usergroups, mock_cvd_dir):
         """test PrepareLaunchCVDCmd."""
diff --git a/create/local_image_remote_instance.py b/create/local_image_remote_instance.py
index d741a4f..20d03aa 100644
--- a/create/local_image_remote_instance.py
+++ b/create/local_image_remote_instance.py
@@ -54,8 +54,7 @@
         Return:
             A string, the path to the host package.
         """
-        dirs_to_check = filter(None,
-                               [os.environ.get(constants.ENV_ANDROID_HOST_OUT)])
+        dirs_to_check = list(filter(None, [os.environ.get(constants.ENV_ANDROID_HOST_OUT)]))
         dist_dir = utils.GetDistDir()
         if dist_dir:
             dirs_to_check.append(dist_dir)
diff --git a/delete/delete.py b/delete/delete.py
index 8318c37..64ca254 100644
--- a/delete/delete.py
+++ b/delete/delete.py
@@ -28,7 +28,6 @@
 from acloud.internal import constants
 from acloud.internal.lib import utils
 from acloud.list import list as list_instances
-from acloud.list import instance as instance_class
 from acloud.public import config
 from acloud.public import device_driver
 from acloud.public import report
@@ -49,11 +48,11 @@
     Try to get directory of "run_cvd" by "ps -o command -p <pid>." command.
     For example: "/tmp/bin/run_cvd"
 
-    Raises:
-        errors.NoExecuteCmd: Can't find stop_cvd.
-
     Returns:
         String of stop_cvd file path.
+
+    Raises:
+        errors.NoExecuteCmd: Can't find stop_cvd.
     """
     process_id = subprocess.check_output(_COMMAND_GET_PROCESS_ID)
     process_info = subprocess.check_output(
@@ -103,7 +102,7 @@
     remote_instance_list = []
     for instance in instances_to_delete:
         if instance.islocal:
-            delete_report = DeleteLocalInstance()
+            delete_report = DeleteLocalInstance(instance, delete_report)
         else:
             remote_instance_list.append(instance.name)
         # Delete ssvnc viewer
@@ -150,32 +149,42 @@
 
 @utils.TimeExecute(function_description="Deleting local instances",
                    result_evaluator=utils.ReportEvaluator)
-def DeleteLocalInstance():
+def DeleteLocalInstance(instance, delete_report=None):
     """Delete local instance.
 
     Delete local instance with stop_cvd command and write delete instance
     information to report.
 
+    Args:
+        instance: instance.LocalInstance object.
+        delete_report: Report object.
+
     Returns:
         A Report instance.
     """
-    delete_report = report.Report(command="delete")
+    if not delete_report:
+        delete_report = report.Report(command="delete")
+
     try:
         with open(os.devnull, "w") as dev_null:
+            cvd_env = os.environ.copy()
+            if instance.instance_dir:
+                cvd_env[constants.ENV_CUTTLEFISH_CONFIG_FILE] = os.path.join(
+                    instance.instance_dir, constants.CUTTLEFISH_CONFIG_FILE)
             subprocess.check_call(
                 utils.AddUserGroupsToCmd(_GetStopCvd(),
                                          constants.LIST_CF_USER_GROUPS),
-                stderr=dev_null, stdout=dev_null, shell=True)
+                stderr=dev_null, stdout=dev_null, shell=True, env=cvd_env)
             delete_report.SetStatus(report.Status.SUCCESS)
             device_driver.AddDeletionResultToReport(
-                delete_report, [constants.LOCAL_INS_NAME], failed=[],
+                delete_report, [instance.name], failed=[],
                 error_msgs=[],
                 resource_name="instance")
+            CleanupSSVncviewer(instance.vnc_port)
     except subprocess.CalledProcessError as e:
         delete_report.AddError(str(e))
         delete_report.SetStatus(report.Status.FAIL)
-    # Only CF supports local instances so assume it's a CF VNC port.
-    CleanupSSVncviewer(constants.CF_VNC_PORT)
+
     return delete_report
 
 
@@ -192,16 +201,12 @@
         A Report instance.
     """
     cfg = config.GetAcloudConfig(args)
-    remote_instances_to_delete = args.instance_names
+    instances_to_delete = args.instance_names
 
-    if remote_instances_to_delete:
-        return DeleteRemoteInstances(cfg, remote_instances_to_delete)
-
-    if args.local_instance:
-        if instance_class.LocalInstance():
-            return DeleteLocalInstance()
-        print("There is no local instance AVD to delete.")
-        return report.Report(command="delete")
+    if instances_to_delete:
+        return DeleteInstances(cfg,
+                               list_instances.GetInstancesFromInstanceNames(
+                                   cfg, instances_to_delete))
 
     if args.adb_port:
         return DeleteInstances(
diff --git a/delete/delete_args.py b/delete/delete_args.py
index dc9c106..9058d28 100644
--- a/delete/delete_args.py
+++ b/delete/delete_args.py
@@ -40,8 +40,8 @@
         dest="instance_names",
         nargs="+",
         required=False,
-        help="The names of the remote instances that need to delete, "
-        "separated by spaces, e.g. --instance-names instance-1 instance-2")
+        help="The names of the instances that need to delete, "
+        "separated by spaces, e.g. --instance-names instance-1 local-instance-1")
     delete_group.add_argument(
         "--all",
         action="store_true",
@@ -49,12 +49,6 @@
         required=False,
         help="If more than 1 AVD instance is found, delete them all.")
     delete_group.add_argument(
-        "--local-instance",
-        action="store_true",
-        dest="local_instance",
-        required=False,
-        help="Only delete the local instance.")
-    delete_group.add_argument(
         "--adb-port", "-p",
         type=int,
         dest="adb_port",
diff --git a/delete/delete_test.py b/delete/delete_test.py
index 916cd22..bb7c10e 100644
--- a/delete/delete_test.py
+++ b/delete/delete_test.py
@@ -31,7 +31,7 @@
     @mock.patch("subprocess.check_output")
     def testGetStopcvd(self, mock_subprocess, mock_path_exist):
         """Test _GetStopCvd."""
-        mock_subprocess.side_effect = ["fack_id",
+        mock_subprocess.side_effect = ["fake_id",
                                        "/tmp/bin/run_cvd"]
         expected_value = "/tmp/bin/stop_cvd"
         self.assertEqual(expected_value, delete._GetStopCvd())
@@ -41,7 +41,10 @@
     def testDeleteLocalInstance(self, mock_subprocess, mock_get_stopcvd):
         """Test DeleteLocalInstance."""
         mock_subprocess.return_value = True
-        delete_report = delete.DeleteLocalInstance()
+        instance_object = mock.MagicMock()
+        instance_object.instance_dir = "fake_instance_dir"
+        instance_object.name = "local-instance"
+        delete_report = delete.DeleteLocalInstance(instance_object)
         self.assertEqual(delete_report.data, {
             "deleted": [
                 {
diff --git a/errors.py b/errors.py
index ca28398..d77ed28 100644
--- a/errors.py
+++ b/errors.py
@@ -245,3 +245,7 @@
 
 class UnsupportedLocalInstanceId(Exception):
     """Unsupported local instance id."""
+
+
+class InvalidInstanceDir(Exception):
+    """Invalid instance dir."""
diff --git a/internal/constants.py b/internal/constants.py
index 895a312..9d91677 100755
--- a/internal/constants.py
+++ b/internal/constants.py
@@ -113,6 +113,7 @@
 
 COMMAND_PS = ["ps", "aux"]
 CMD_LAUNCH_CVD = "launch_cvd"
+CMD_PGREP = "pgrep"
 CMD_STOP_CVD = "stop_cvd"
 CMD_RUN_CVD = "run_cvd"
 ENV_ANDROID_BUILD_TOP = "ANDROID_BUILD_TOP"
@@ -144,6 +145,7 @@
 INS_KEY_IS_LOCAL = "remote"
 INS_STATUS_RUNNING = "RUNNING"
 LOCAL_INS_NAME = "local-instance"
+LOCAL_INS_HOME_PREFIX = "instance_home_"
 ENV_CUTTLEFISH_CONFIG_FILE = "CUTTLEFISH_CONFIG_FILE"
 CUTTLEFISH_CONFIG_FILE = "cuttlefish_config.json"
 
@@ -151,7 +153,6 @@
 TOOL_NAME = "acloud"
 EXIT_BY_USER = 1
 EXIT_BY_ERROR = -99
-RE_LAUNCH_CVD_PATTERN = "launch_cvd.*%(arg_name)s %(arg_value)s"
 
 # For reuse gce instance
 SELECT_ONE_GCE_INSTANCE = "select_one_gce_instance"
diff --git a/internal/lib/cvd_compute_client_multi_stage.py b/internal/lib/cvd_compute_client_multi_stage.py
index 44c0e90..98783a4 100644
--- a/internal/lib/cvd_compute_client_multi_stage.py
+++ b/internal/lib/cvd_compute_client_multi_stage.py
@@ -175,7 +175,7 @@
         if avd_spec:
             if avd_spec.instance_name_to_reuse:
                 self.StopCvd()
-                self.CleanUpImages()
+                self.CleanUp()
             return instance
 
         # TODO: Remove following code after create_cf deprecated.
@@ -277,17 +277,18 @@
         except subprocess.CalledProcessError as e:
             logger.debug("Failed to stop_cvd (possibly no running device): %s", e)
 
-    def CleanUpImages(self):
-        """Clean up the images on the existing instance.
+    def CleanUp(self):
+        """Clean up the files/folders on the existing instance.
 
-        If previous AVD have these images, reusing the instance may have
-        side effects if didn't clean it.
+        If previous AVD have these files/folders, reusing the instance may have
+        side effects if not cleaned. The path in the instance is /home/vsoc-01/*
+        if the GCE user is vsoc-01.
         """
-        ssh_command = "/bin/rm ./*.img"
+        ssh_command = "'/bin/rm -rf /home/%s/*'" % constants.GCE_USER
         try:
             self._ssh.Run(ssh_command)
         except subprocess.CalledProcessError as e:
-            logger.debug("Failed to clean up the images failed: %s", e)
+            logger.debug("Failed to clean up the files/folders: %s", e)
 
     @utils.TimeExecute(function_description="Launching AVD(s) and waiting for boot up",
                        result_evaluator=utils.BootEvaluator)
diff --git a/internal/lib/gcompute_client.py b/internal/lib/gcompute_client.py
index 5709445..bde5ac2 100755
--- a/internal/lib/gcompute_client.py
+++ b/internal/lib/gcompute_client.py
@@ -1584,7 +1584,7 @@
             # in the metadata. There may not be an actual ssh key value so
             # that's why we filter for None to avoid an empty line in front.
             ssh_key_item[_METADATA_KEY_VALUE] = "\n".join(
-                filter(None, [ssh_key_item[_METADATA_KEY_VALUE], entry]))
+                list(filter(None, [ssh_key_item[_METADATA_KEY_VALUE], entry])))
         else:
             # Since there is no ssh key item in the metadata, we need to add it in.
             ssh_key_item = {_METADATA_KEY: _SSH_KEYS_NAME,
diff --git a/internal/lib/goldfish_compute_client.py b/internal/lib/goldfish_compute_client.py
index 926cdac..d9d1d20 100644
--- a/internal/lib/goldfish_compute_client.py
+++ b/internal/lib/goldfish_compute_client.py
@@ -122,6 +122,17 @@
                 raise errors.DeviceBootError(
                     "Emulator timed out while booting.")
 
+    @staticmethod
+    def GetKernelBuildArtifact(target):
+        if target == "kernel":
+            return "bzImage"
+        if target == "kernel_x86_64":
+            return "bzImage"
+        if target == "kernel_aarch64":
+            return "Image.gz"
+        raise errors.DeviceBootError(
+            "Don't know the artifact name for '%s' target" % target)
+
     # pylint: disable=too-many-locals,arguments-differ
     # TODO: Refactor CreateInstance to pass in an object instead of all these args.
     def CreateInstance(self,
@@ -133,6 +144,7 @@
                        build_id,
                        kernel_branch=None,
                        kernel_build_id=None,
+                       kernel_build_target=None,
                        emulator_branch=None,
                        emulator_build_id=None,
                        blank_data_disk_size_gb=None,
@@ -152,6 +164,7 @@
             build_id: String, build id, a string, e.g. "2263051", "P2804227"
             kernel_branch: String, kernel branch name.
             kernel_build_id: String, kernel build id.
+            kernel_build_target: kernel target, e.g. "kernel_x86_64"
             emulator_branch: String, emulator branch name, e.g."aosp-emu-master-dev"
             emulator_build_id: String, emulator build id, a string, e.g. "2263051", "P2804227"
             blank_data_disk_size_gb: Integer, size of the blank data disk in GB.
@@ -181,9 +194,12 @@
         metadata["cvd_01_fetch_android_build_target"] = build_target
         metadata["cvd_01_fetch_android_bid"] = "{branch}/{build_id}".format(
             branch=branch, build_id=build_id)
-        if kernel_branch and kernel_build_id:
+        if kernel_branch and kernel_build_id and kernel_build_target:
             metadata["cvd_01_fetch_kernel_bid"] = "{branch}/{build_id}".format(
                 branch=kernel_branch, build_id=kernel_build_id)
+            metadata["cvd_01_fetch_kernel_build_target"] = kernel_build_target
+            metadata["cvd_01_fetch_kernel_build_artifact"] = (
+                self.GetKernelBuildArtifact(kernel_build_target))
             metadata["cvd_01_use_custom_kernel"] = "true"
         if emulator_branch and emulator_build_id:
             metadata[
diff --git a/internal/lib/goldfish_compute_client_test.py b/internal/lib/goldfish_compute_client_test.py
index 8b67088..cfee21f 100644
--- a/internal/lib/goldfish_compute_client_test.py
+++ b/internal/lib/goldfish_compute_client_test.py
@@ -37,6 +37,8 @@
     BUILD_ID = "2263051"
     KERNEL_BRANCH = "kernel-p-dev-android-goldfish-4.14-x86-64"
     KERNEL_BUILD_ID = "112233"
+    KERNEL_BUILD_TARGET = "kernel_x86_64"
+    KERNEL_BUILD_ARTIFACT = "bzImage"
     EMULATOR_BRANCH = "aosp-emu-master-dev"
     EMULATOR_BUILD_ID = "1234567"
     DPI = 160
@@ -105,6 +107,8 @@
             "cvd_01_fetch_kernel_bid":
                 "{branch}/{build_id}".format(
                     branch=self.KERNEL_BRANCH, build_id=self.KERNEL_BUILD_ID),
+            "cvd_01_fetch_kernel_build_target": self.KERNEL_BUILD_TARGET,
+            "cvd_01_fetch_kernel_build_artifact": self.KERNEL_BUILD_ARTIFACT,
             "cvd_01_use_custom_kernel": "true",
             "cvd_01_fetch_emulator_bid":
                 "{branch}/{build_id}".format(
@@ -120,8 +124,11 @@
 
         self.goldfish_compute_client.CreateInstance(
             self.INSTANCE, self.IMAGE, self.IMAGE_PROJECT, self.TARGET,
-            self.BRANCH, self.BUILD_ID, self.KERNEL_BRANCH,
-            self.KERNEL_BUILD_ID, self.EMULATOR_BRANCH,
+            self.BRANCH, self.BUILD_ID,
+            self.KERNEL_BRANCH,
+            self.KERNEL_BUILD_ID,
+            self.KERNEL_BUILD_TARGET,
+            self.EMULATOR_BRANCH,
             self.EMULATOR_BUILD_ID, self.EXTRA_DATA_DISK_SIZE_GB, self.GPU,
             extra_scopes=self.EXTRA_SCOPES,
             tags=self.TAGS)
diff --git a/internal/lib/utils.py b/internal/lib/utils.py
index af0d234..ff7e3a8 100755
--- a/internal/lib/utils.py
+++ b/internal/lib/utils.py
@@ -78,7 +78,6 @@
 
 _VNC_BIN = "ssvnc"
 _CMD_KILL = ["pkill", "-9", "-f"]
-_CMD_PGREP = "pgrep"
 _CMD_SG = "sg "
 _CMD_START_VNC = "%(bin)s vnc://127.0.0.1:%(port)d"
 _CMD_INSTALL_SSVNC = "sudo apt-get --assume-yes install ssvnc"
@@ -1028,7 +1027,7 @@
     """
     try:
         with open(os.devnull, "w") as dev_null:
-            subprocess.check_call([_CMD_PGREP, "-af", command],
+            subprocess.check_call([constants.CMD_PGREP, "-af", command],
                                   stderr=dev_null, stdout=dev_null)
         return True
     except subprocess.CalledProcessError:
diff --git a/list/instance.py b/list/instance.py
index 005abcf..7b58792 100644
--- a/list/instance.py
+++ b/list/instance.py
@@ -33,6 +33,7 @@
 import os
 import re
 import subprocess
+import tempfile
 
 # pylint: disable=import-error
 import dateutil.parser
@@ -46,6 +47,9 @@
 
 logger = logging.getLogger(__name__)
 
+_ACLOUD_CVD_TEMP = os.path.join(tempfile.gettempdir(), "acloud_cvd_temp")
+_CVD_RUNTIME_FOLDER_NAME = "cuttlefish_runtime"
+_LOCAL_INSTANCE_HOME = "instance_home_%s"
 _MSG_UNABLE_TO_CALCULATE = "Unable to calculate"
 _RE_GROUP_ADB = "local_adb_port"
 _RE_GROUP_VNC = "local_vnc_port"
@@ -62,6 +66,53 @@
                                                    constants.ADB_PORT])
 
 
+def GetLocalInstanceHomeDir(local_instance_id):
+    """Get local instance home dir accroding to instance id.
+
+    Args:
+        local_instance_id: Integer of instance id.
+
+    Return:
+        String, path of instance home dir.
+    """
+    return os.path.join(_ACLOUD_CVD_TEMP,
+                        _LOCAL_INSTANCE_HOME % local_instance_id)
+
+
+def GetLocalInstanceRuntimeDir(local_instance_id):
+    """Get instance runtime dir
+
+    Args:
+        local_instance_id: Integer of instance id.
+
+    Return:
+        String, path of instance runtime dir.
+    """
+    return os.path.join(GetLocalInstanceHomeDir(local_instance_id),
+                        _CVD_RUNTIME_FOLDER_NAME)
+
+
+def GetCuttlefishRuntimeConfig(local_instance_id):
+    """Get and parse cuttlefish_config.json.
+
+    Args:
+        local_instance_id: Integer of instance id.
+
+    Returns:
+        A dictionary that parsed from cuttlefish runtime config.
+
+    Raises:
+        errors.ConfigError: if file not found or config load failed.
+    """
+    runtime_cf_config_path = os.path.join(GetLocalInstanceRuntimeDir(
+        local_instance_id), constants.CUTTLEFISH_CONFIG_FILE)
+    if not os.path.exists(runtime_cf_config_path):
+        raise errors.ConfigError(
+            "file does not exist: %s" % runtime_cf_config_path)
+    with open(runtime_cf_config_path, "r") as cf_config:
+        return json.load(cf_config)
+
+
 def GetLocalPortsbyInsId(local_instance_id):
     """Get vnc and adb port by local instance id.
 
@@ -105,21 +156,25 @@
 class Instance(object):
     """Class to store data of instance."""
 
-    def __init__(self):
-        self._name = None
-        self._fullname = None
-        self._status = None
-        self._display = None  # Resolution and dpi
-        self._ip = None
-        self._adb_port = None  # adb port which is forwarding to remote
-        self._vnc_port = None  # vnc port which is forwarding to remote
-        self._ssh_tunnel_is_connected = None  # True if ssh tunnel is still connected
-        self._createtime = None
-        self._elapsed_time = None
-        self._avd_type = None
-        self._avd_flavor = None
-        self._is_local = None  # True if this is a local instance
-        self._device_information = None
+    def __init__(self, name, fullname, display, ip, status=None, adb_port=None,
+                 vnc_port=None, ssh_tunnel_is_connected=None, createtime=None,
+                 elapsed_time=None, avd_type=None, avd_flavor=None,
+                 is_local=False, device_information=None):
+        self._name = name
+        self._fullname = fullname
+        self._status = status
+        self._display = display  # Resolution and dpi
+        self._ip = ip
+        self._adb_port = adb_port  # adb port which is forwarding to remote
+        self._vnc_port = vnc_port  # vnc port which is forwarding to remote
+        # True if ssh tunnel is still connected
+        self._ssh_tunnel_is_connected = ssh_tunnel_is_connected
+        self._createtime = createtime
+        self._elapsed_time = elapsed_time
+        self._avd_type = avd_type
+        self._avd_flavor = avd_flavor
+        self._is_local = is_local  # True if this is a local instance
+        self._device_information = device_information
 
     def __repr__(self):
         """Return full name property for print."""
@@ -214,95 +269,73 @@
         """Return if it is a local instance."""
         return self._is_local
 
+    @property
+    def adb_port(self):
+        """Return adb_port."""
+        return self._adb_port
+
+    @property
+    def vnc_port(self):
+        """Return vnc_port."""
+        return self._vnc_port
+
 
 class LocalInstance(Instance):
     """Class to store data of local instance."""
 
-    # pylint: disable=protected-access
-    def __new__(cls):
+    def __init__(self, local_instance_id, x_res, y_res, dpi, create_time,
+                 ins_dir=None):
         """Initialize a localInstance object.
 
-        Gather local instance information from launch_cvd process.
-
-        returns:
-            Instance object if launch_cvd process is found otherwise return None.
+        Args:
+            local_instance_id: Integer of instance id.
+            x_res: Integer of x dimension.
+            y_res: Integer of y dimension.
+            dpi: Integer of dpi.
+            date_str: String of create time.
+            ins_dir: String, path of instance idr.
         """
-        # Running instances on local is not supported on all OS.
-        if not utils.IsSupportedPlatform():
-            return None
+        display = ("%sx%s (%s)" % (x_res, y_res, dpi))
+        elapsed_time = _GetElapsedTime(create_time) if create_time else None
+        name = "%s-%d" % (constants.LOCAL_INS_NAME, local_instance_id)
+        local_ports = GetLocalPortsbyInsId(local_instance_id)
+        fullname = (_FULL_NAME_STRING %
+                    {"device_serial": "127.0.0.1:%d" % local_ports.adb_port,
+                     "instance_name": name,
+                     "elapsed_time": elapsed_time})
+        adb_device = AdbTools(local_ports.adb_port)
+        device_information = None
+        if adb_device.IsAdbConnected():
+            device_information = adb_device.device_information
 
-        process_output = subprocess.check_output(_COMMAND_PS_LAUNCH_CVD)
-        for line in process_output.splitlines():
-            match = _RE_RUN_CVD.match(line)
-            if match:
-                local_instance = Instance()
-                cf_runtime_config_dict = GetCuttlefishRuntimeConfig()
-                x_res = cf_runtime_config_dict["x_res"]
-                y_res = cf_runtime_config_dict["y_res"]
-                dpi = cf_runtime_config_dict["dpi"]
-                date_str = match.group("date_str").strip()
-                local_instance._name = constants.LOCAL_INS_NAME
-                local_instance._createtime = date_str
-                local_instance._elapsed_time = _GetElapsedTime(date_str)
-                local_instance._fullname = (_FULL_NAME_STRING %
-                                            {"device_serial": "127.0.0.1:%d" %
-                                                              constants.CF_ADB_PORT,
-                                             "instance_name": local_instance._name,
-                                             "elapsed_time": local_instance._elapsed_time})
-                local_instance._avd_type = constants.TYPE_CF
-                local_instance._ip = "127.0.0.1"
-                local_instance._status = constants.INS_STATUS_RUNNING
-                local_instance._adb_port = constants.CF_ADB_PORT
-                local_instance._vnc_port = constants.CF_VNC_PORT
-                local_instance._display = ("%sx%s (%s)" % (x_res, y_res, dpi))
-                local_instance._is_local = True
-                local_instance._ssh_tunnel_is_connected = True
+        super(LocalInstance, self).__init__(
+            name=name, fullname=fullname, display=display, ip="127.0.0.1",
+            status=constants.INS_STATUS_RUNNING, adb_port=local_ports.adb_port,
+            vnc_port=local_ports.vnc_port, createtime=create_time,
+            elapsed_time=elapsed_time, avd_type=constants.TYPE_CF,
+            is_local=True, device_information=device_information)
 
-                adb_device = AdbTools(constants.CF_ADB_PORT)
-                if adb_device.IsAdbConnected():
-                    local_instance._device_information = adb_device.device_information
-                return local_instance
-        return None
+        # LocalInstance class properties
+        self._instance_dir = ins_dir
 
-def GetCuttlefishRuntimeConfig():
-    """Get and parse cuttlefish_config.json.
+    @property
+    def instance_dir(self):
+        """Return _instance_dir."""
+        return self._instance_dir
 
-    Returns:
-        Dict parsing json file from cuttlefish runtime config.
-
-    Raises:
-        errors.ConfigError: if file not found or config load failed.
-    """
-    runtime_cf_config_path = os.path.join(os.path.expanduser("~"),
-                                          "cuttlefish_runtime",
-                                          "cuttlefish_config.json")
-    if os.path.exists(runtime_cf_config_path):
-        with open(runtime_cf_config_path, "r") as cf_config:
-            return json.load(cf_config)
-    else:
-        raise errors.ConfigError("file does not exist: %s" % runtime_cf_config_path)
-    raise errors.ConfigError("Could not load cuttlefish_config.json.")
 
 class RemoteInstance(Instance):
     """Class to store data of remote instance."""
 
+    # pylint: disable=too-many-locals
     def __init__(self, gce_instance):
         """Process the args into class vars.
 
-        RemoteInstace initialized by gce dict object.
+        RemoteInstace initialized by gce dict object. We parse the required data
+        from gce_instance to local variables.
         Reference:
         https://cloud.google.com/compute/docs/reference/rest/v1/instances/get
 
-        Args:
-            gce_instance: dict object queried from gce.
-        """
-        super(RemoteInstance, self).__init__()
-        self._ProcessGceInstance(gce_instance)
-        self._is_local = False
-
-    def _ProcessGceInstance(self, gce_instance):
-        """Parse the required data from gce_instance to local variables.
-
         We also gather more details on client side including the forwarding adb
         port and vnc port which will be used to determine the status of ssh
         tunnel connection.
@@ -314,13 +347,13 @@
         - Terminated: If we can't retrieve the public ip from gce instance.
 
         Args:
-           gce_instance: dict object queried from gce.
+            gce_instance: dict object queried from gce.
         """
-        self._name = gce_instance.get(constants.INS_KEY_NAME)
+        name = gce_instance.get(constants.INS_KEY_NAME)
 
-        self._createtime = gce_instance.get(constants.INS_KEY_CREATETIME)
-        self._elapsed_time = _GetElapsedTime(self._createtime)
-        self._status = gce_instance.get(constants.INS_KEY_STATUS)
+        create_time = gce_instance.get(constants.INS_KEY_CREATETIME)
+        elapsed_time = _GetElapsedTime(create_time)
+        status = gce_instance.get(constants.INS_KEY_STATUS)
 
         ip = None
         for network_interface in gce_instance.get("networkInterfaces"):
@@ -328,44 +361,56 @@
                 ip = access_config.get("natIP")
 
         # Get metadata
+        display = None
+        avd_type = None
+        avd_flavor = None
         for metadata in gce_instance.get("metadata", {}).get("items", []):
             key = metadata["key"]
             value = metadata["value"]
             if key == constants.INS_KEY_DISPLAY:
-                self._display = value
+                display = value
             elif key == constants.INS_KEY_AVD_TYPE:
-                self._avd_type = value
+                avd_type = value
             elif key == constants.INS_KEY_AVD_FLAVOR:
-                self._avd_flavor = value
+                avd_flavor = value
 
         # Find ssl tunnel info.
+        adb_port = None
+        vnc_port = None
+        device_information = None
         if ip:
-            forwarded_ports = self.GetAdbVncPortFromSSHTunnel(ip,
-                                                              self._avd_type)
-            self._ip = ip
-            self._adb_port = forwarded_ports.adb_port
-            self._vnc_port = forwarded_ports.vnc_port
-            self._ssh_tunnel_is_connected = self._adb_port is not None
+            forwarded_ports = self.GetAdbVncPortFromSSHTunnel(ip, avd_type)
+            adb_port = forwarded_ports.adb_port
+            vnc_port = forwarded_ports.vnc_port
+            ssh_tunnel_is_connected = adb_port is not None
 
-            adb_device = AdbTools(self._adb_port)
+            adb_device = AdbTools(adb_port)
             if adb_device.IsAdbConnected():
-                self._device_information = adb_device.device_information
-                self._fullname = (_FULL_NAME_STRING %
-                                  {"device_serial": "127.0.0.1:%d" % self._adb_port,
-                                   "instance_name": self._name,
-                                   "elapsed_time": self._elapsed_time})
+                device_information = adb_device.device_information
+                fullname = (_FULL_NAME_STRING %
+                            {"device_serial": "127.0.0.1:%d" % adb_port,
+                             "instance_name": name,
+                             "elapsed_time": elapsed_time})
             else:
-                self._fullname = (_FULL_NAME_STRING %
-                                  {"device_serial": "not connected",
-                                   "instance_name": self._name,
-                                   "elapsed_time": self._elapsed_time})
+                fullname = (_FULL_NAME_STRING %
+                            {"device_serial": "not connected",
+                             "instance_name": name,
+                             "elapsed_time": elapsed_time})
         # If instance is terminated, its ip is None.
         else:
-            self._ssh_tunnel_is_connected = False
-            self._fullname = (_FULL_NAME_STRING %
-                              {"device_serial": "terminated",
-                               "instance_name": self._name,
-                               "elapsed_time": self._elapsed_time})
+            ssh_tunnel_is_connected = False
+            fullname = (_FULL_NAME_STRING %
+                        {"device_serial": "terminated",
+                         "instance_name": name,
+                         "elapsed_time": elapsed_time})
+
+        super(RemoteInstance, self).__init__(
+            name=name, fullname=fullname, display=display, ip=ip, status=status,
+            adb_port=adb_port, vnc_port=vnc_port,
+            ssh_tunnel_is_connected=ssh_tunnel_is_connected,
+            createtime=create_time, elapsed_time=elapsed_time, avd_type=avd_type,
+            avd_flavor=avd_flavor, is_local=False,
+            device_information=device_information)
 
     @staticmethod
     def GetAdbVncPortFromSSHTunnel(ip, avd_type):
diff --git a/list/instance_test.py b/list/instance_test.py
index af1960b..8c9e1ca 100644
--- a/list/instance_test.py
+++ b/list/instance_test.py
@@ -61,21 +61,23 @@
         """"Test get local instance info from launch_cvd process."""
         self.Patch(subprocess, "check_output", return_value=self.PS_LAUNCH_CVD)
         self.Patch(instance, "_GetElapsedTime", return_value="fake_time")
-        self.Patch(instance, "GetCuttlefishRuntimeConfig",
-                   return_value=self.PS_RUNTIME_CF_CONFIG)
-        local_instance = instance.LocalInstance()
-        self.assertEqual(constants.LOCAL_INS_NAME, local_instance.name)
+        local_instance = instance.LocalInstance(2,
+                                                "1080",
+                                                "1920",
+                                                "480",
+                                                "Sat Nov 10 21:55:10 2018",
+                                                "fake_instance_dir")
+        self.assertEqual(constants.LOCAL_INS_NAME + "-2", local_instance.name)
         self.assertEqual(True, local_instance.islocal)
         self.assertEqual("1080x1920 (480)", local_instance.display)
         self.assertEqual("Sat Nov 10 21:55:10 2018", local_instance.createtime)
-        expected_full_name = "device serial: 127.0.0.1:%s (%s) elapsed time: %s" % (
-            constants.CF_ADB_PORT, constants.LOCAL_INS_NAME, "fake_time")
+        expected_full_name = ("device serial: 127.0.0.1:%s (%s) elapsed time: %s"
+                              % ("6521",
+                                 constants.LOCAL_INS_NAME + "-2",
+                                 "fake_time"))
         self.assertEqual(expected_full_name, local_instance.fullname)
-
-        # test return None if no launch_cvd process found
-        self.Patch(subprocess, "check_output", return_value="no launch_cvd "
-                                                            "found")
-        self.assertEqual(None, instance.LocalInstance())
+        self.assertEqual(6521, local_instance.forwarding_adb_port)
+        self.assertEqual(6445, local_instance.forwarding_vnc_port)
 
     def testGetElapsedTime(self):
         """Test _GetElapsedTime"""
diff --git a/list/list.py b/list/list.py
index ce45c8c..05596df 100644
--- a/list/list.py
+++ b/list/list.py
@@ -20,6 +20,8 @@
 from __future__ import print_function
 import getpass
 import logging
+import re
+import subprocess
 
 from acloud import errors
 from acloud.internal import constants
@@ -32,6 +34,31 @@
 
 logger = logging.getLogger(__name__)
 
+_COMMAND_PS_LAUNCH_CVD = ["ps", "-wweo", "lstart,cmd"]
+_RE_LOCAL_INSTANCE_ID = re.compile(r".+instance_home_(?P<ins_id>\d+).+")
+_RE_LOCAL_CVD_PORT = re.compile(r"^127\.0\.0\.1:65(?P<cvd_port_suffix>\d{2})\s+")
+
+
+def GetActiveCVDIds():
+    """Get active local cvd ids from adb devices.
+
+    The adb port of local instance will be decided according to instance id.
+    The rule of adb port will be '6520 + [instance id] - 1'. So we grep last
+    two digits of port and calculate the instance id.
+
+    Return:
+        List of cvd id.
+    """
+    local_cvd_ids = []
+    adb_cmd = [constants.ADB_BIN, "devices"]
+    device_info = subprocess.check_output(adb_cmd)
+    for device in device_info.splitlines():
+        match = _RE_LOCAL_CVD_PORT.match(device)
+        if match:
+            cvd_serial = match.group("cvd_port_suffix")
+            local_cvd_ids.append(int(cvd_serial) - 19)
+    return local_cvd_ids
+
 
 def _ProcessInstances(instance_list):
     """Get more details of remote instances.
@@ -110,6 +137,64 @@
     return _ProcessInstances(all_instances)
 
 
+def GetLocalInstances():
+    """Look for local instances.
+
+    Gather local instances information from cuttlefish runtime config.
+
+    Returns:
+        instance_list: List of local instances.
+    """
+    # Running instances on local is not supported on all OS.
+    if not utils.IsSupportedPlatform():
+        return None
+
+    local_cvd_ids = GetActiveCVDIds()
+    local_instance_list = []
+    for cvd_id in local_cvd_ids:
+        ins_dir = x_res = y_res = dpi = cf_runtime_config_dict = None
+        try:
+            cf_runtime_config_dict = instance.GetCuttlefishRuntimeConfig(cvd_id)
+        except errors.ConfigError:
+            logger.error("Instance[id:%d] dir not found!", cvd_id)
+
+        if cf_runtime_config_dict:
+            ins_dir = instance.GetLocalInstanceRuntimeDir(cvd_id)
+            x_res = cf_runtime_config_dict["x_res"]
+            y_res = cf_runtime_config_dict["y_res"]
+            dpi = cf_runtime_config_dict["dpi"]
+        # TODO(143063678), there's no createtime info in
+        # cuttlefish_config.json so far.
+        local_instance_list.append(instance.LocalInstance(cvd_id,
+                                                          x_res,
+                                                          y_res,
+                                                          dpi,
+                                                          None,
+                                                          ins_dir))
+    return local_instance_list
+
+
+def _GetIdFromInstanceDirStr(instance_dir):
+    """Look for instance id from the path of instance dir.
+
+    Args:
+        instance_dir: String, path of instance_dir.
+
+    Returns:
+        Integer of instance id.
+
+    Raises:
+        errors.InvalidInstanceDir: Invalid instance idr.
+    """
+    match = _RE_LOCAL_INSTANCE_ID.match(instance_dir)
+    if match:
+        return int(match.group("ins_id"))
+
+    raise errors.InvalidInstanceDir("Instance dir is invalid:%s. local AVD "
+                                    "launched outside acloud is not supported"
+                                    % instance_dir)
+
+
 def GetInstances(cfg):
     """Look for remote/local instances.
 
@@ -120,9 +205,9 @@
         instance_list: List of instances.
     """
     instances_list = GetRemoteInstances(cfg)
-    local_instance = instance.LocalInstance()
-    if local_instance:
-        instances_list.append(local_instance)
+    local_instances = GetLocalInstances()
+    if local_instances:
+        instances_list.extend(local_instances)
 
     return instances_list
 
diff --git a/public/acloud_main.py b/public/acloud_main.py
index 65e649b..c80b995 100644
--- a/public/acloud_main.py
+++ b/public/acloud_main.py
@@ -403,6 +403,7 @@
             emulator_branch=args.emulator_branch,
             kernel_build_id=args.kernel_build_id,
             kernel_branch=args.kernel_branch,
+            kernel_build_target=args.kernel_build_target,
             gpu=args.gpu,
             num=args.num,
             serial_log_file=args.serial_log_file,
diff --git a/public/actions/create_goldfish_action.py b/public/actions/create_goldfish_action.py
index 36124f8..c5b942a 100644
--- a/public/actions/create_goldfish_action.py
+++ b/public/actions/create_goldfish_action.py
@@ -67,6 +67,7 @@
                  emulator_build_id,
                  kernel_build_id=None,
                  kernel_branch=None,
+                 kernel_build_target=None,
                  gpu=None,
                  avd_spec=None,
                  tags=None,
@@ -113,7 +114,8 @@
         self.emulator_build_info = self._build_client.GetBuildInfo(
             emulator_build_target, emulator_build_id, emulator_branch)
         self.kernel_build_info = self._build_client.GetBuildInfo(
-            cfg.kernel_build_target, kernel_build_id, kernel_branch)
+            kernel_build_target or cfg.kernel_build_target, kernel_build_id,
+            kernel_branch)
 
     def GetBuildInfoDict(self):
         """Get build info dictionary.
@@ -159,6 +161,7 @@
             emulator_build_id=self.emulator_build_info.build_id,
             kernel_branch=self.kernel_build_info.branch,
             kernel_build_id=self.kernel_build_info.build_id,
+            kernel_build_target=self.kernel_build_info.build_target,
             gpu=self._gpu,
             blank_data_disk_size_gb=self._blank_data_disk_size_gb,
             avd_spec=self._avd_spec,
@@ -232,6 +235,7 @@
                   emulator_branch=None,
                   kernel_build_id=None,
                   kernel_branch=None,
+                  kernel_build_target=None,
                   gpu=None,
                   num=1,
                   serial_log_file=None,
@@ -252,6 +256,7 @@
         gpu: String, GPU to attach to the device or None. e.g. "nvidia-k80"
         kernel_build_id: Kernel build id, a string.
         kernel_branch: Kernel branch name, a string.
+        kernel_build_target: Kernel build artifact, a string.
         num: Integer, Number of devices to create.
         serial_log_file: String, A path to a file where serial output should
                         be saved to.
@@ -313,20 +318,22 @@
     logger.info(
         "Creating a goldfish device in project %s, build_target: %s, "
         "build_id: %s, emulator_bid: %s, kernel_build_id: %s, "
-        "kernel_branh: %s, GPU: %s, num: %s, "
+        "kernel_branch: %s, kernel_build_target: %s, GPU: %s, num: %s, "
         "serial_log_file: %s, "
         "autoconnect: %s", cfg.project, build_target, build_id,
-        emulator_build_id, kernel_build_id, kernel_branch, gpu, num,
-        serial_log_file, autoconnect)
+        emulator_build_id, kernel_build_id, kernel_branch, kernel_build_target,
+        gpu, num, serial_log_file, autoconnect)
 
-    device_factory = GoldfishDeviceFactory(cfg, build_target, build_id,
-                                           cfg.emulator_build_target,
-                                           emulator_build_id, gpu=gpu,
-                                           avd_spec=avd_spec, tags=tags,
-                                           branch=branch,
-                                           emulator_branch=emulator_branch,
-                                           kernel_build_id=kernel_build_id,
-                                           kernel_branch=kernel_branch)
+    device_factory = GoldfishDeviceFactory(
+        cfg, build_target, build_id,
+        cfg.emulator_build_target,
+        emulator_build_id, gpu=gpu,
+        avd_spec=avd_spec, tags=tags,
+        branch=branch,
+        emulator_branch=emulator_branch,
+        kernel_build_id=kernel_build_id,
+        kernel_branch=kernel_branch,
+        kernel_build_target=kernel_build_target)
 
     return common_operations.CreateDevices("create_gf", cfg, device_factory,
                                            num, constants.TYPE_GF,
diff --git a/public/actions/create_goldfish_action_test.py b/public/actions/create_goldfish_action_test.py
index fa04ee2..d031167 100644
--- a/public/actions/create_goldfish_action_test.py
+++ b/public/actions/create_goldfish_action_test.py
@@ -123,7 +123,10 @@
         report = create_goldfish_action.CreateDevices(
             none_avd_spec, cfg, build_target=self.BUILD_TARGET,
             build_id=self.BUILD_ID, emulator_build_id=self.EMULATOR_BUILD_ID,
-            gpu=self.GPU, kernel_build_id=self.KERNEL_BUILD_ID)
+            gpu=self.GPU,
+            kernel_branch=self.KERNEL_BRANCH,
+            kernel_build_id=self.KERNEL_BUILD_ID,
+            kernel_build_target=self.KERNEL_BUILD_TARGET)
 
         # Verify
         self.compute_client.CreateInstance.assert_called_with(
@@ -138,6 +141,7 @@
             emulator_build_id=self.EMULATOR_BUILD_ID,
             kernel_branch=self.KERNEL_BRANCH,
             kernel_build_id=self.KERNEL_BUILD_ID,
+            kernel_build_target=self.KERNEL_BUILD_TARGET,
             gpu=self.GPU,
             avd_spec=none_avd_spec,
             extra_scopes=self.EXTRA_SCOPES,
@@ -193,6 +197,7 @@
             emulator_build_id=self.EMULATOR_BUILD_ID,
             kernel_branch=self.KERNEL_BRANCH,
             kernel_build_id=self.KERNEL_BUILD_ID,
+            kernel_build_target=self.KERNEL_BUILD_TARGET,
             gpu=self.GPU,
             avd_spec=self.avd_spec,
             extra_scopes=self.EXTRA_SCOPES,
@@ -239,7 +244,9 @@
             emulator_branch=None,
             gpu=self.GPU,
             branch=None,
-            kernel_build_id=self.KERNEL_BUILD_ID)
+            kernel_branch=self.KERNEL_BRANCH,
+            kernel_build_id=self.KERNEL_BUILD_ID,
+            kernel_build_target=self.KERNEL_BUILD_TARGET)
 
         # Verify
         self.compute_client.CreateInstance.assert_called_with(
@@ -254,6 +261,7 @@
             emulator_build_id=self.EMULATOR_BUILD_ID,
             kernel_branch=self.KERNEL_BRANCH,
             kernel_build_id=self.KERNEL_BUILD_ID,
+            kernel_build_target=self.KERNEL_BUILD_TARGET,
             gpu=self.GPU,
             avd_spec=none_avd_spec,
             extra_scopes=self.EXTRA_SCOPES,
@@ -307,6 +315,7 @@
             emulator_build_id=self.EMULATOR_BUILD_ID,
             kernel_branch=self.KERNEL_BRANCH,
             kernel_build_id=self.KERNEL_BUILD_ID,
+            kernel_build_target=self.KERNEL_BUILD_TARGET,
             gpu=self.GPU,
             avd_spec=self.avd_spec,
             extra_scopes=self.EXTRA_SCOPES,
@@ -363,6 +372,7 @@
             emulator_build_id=self.EMULATOR_BUILD_ID,
             kernel_branch=self.KERNEL_BRANCH,
             kernel_build_id=self.KERNEL_BUILD_ID,
+            kernel_build_target=self.KERNEL_BUILD_TARGET,
             gpu=self.GPU,
             avd_spec=none_avd_spec,
             extra_scopes=self.EXTRA_SCOPES,
@@ -416,6 +426,7 @@
             emulator_build_id=self.EMULATOR_BUILD_ID,
             kernel_branch=self.KERNEL_BRANCH,
             kernel_build_id=self.KERNEL_BUILD_ID,
+            kernel_build_target=self.KERNEL_BUILD_TARGET,
             gpu=self.GPU,
             avd_spec=self.avd_spec,
             extra_scopes=self.EXTRA_SCOPES,
diff --git a/public/actions/remote_instance_cf_device_factory.py b/public/actions/remote_instance_cf_device_factory.py
index 8a539c1..74f5ca7 100644
--- a/public/actions/remote_instance_cf_device_factory.py
+++ b/public/actions/remote_instance_cf_device_factory.py
@@ -250,3 +250,26 @@
             and the value is an errors.DeviceBootError object.
         """
         return self._compute_client.all_failures
+
+    def GetBuildInfoDict(self):
+        """Get build info dictionary.
+
+        Returns:
+          A build info dictionary.
+        """
+        build_info_dict = {
+            key: val for key, val in self._avd_spec.remote_image.items() if val}
+
+        # kernel_target have default value "kernel". If user provide kernel_build_id
+        # or kernel_branch, then start to process kernel image.
+        if (self._avd_spec.kernel_build_info[constants.BUILD_ID]
+                or self._avd_spec.kernel_build_info[constants.BUILD_BRANCH]):
+            build_info_dict.update(
+                {"kernel_%s" % key: val
+                 for key, val in self._avd_spec.kernel_build_info.items() if val}
+            )
+        build_info_dict.update(
+            {"system_%s" % key: val
+             for key, val in self._avd_spec.system_build_info.items() if val}
+        )
+        return build_info_dict