Home | History | Annotate | Download | only in device
      1 /*
      2  * Copyright (C) 2008 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.hierarchyviewer.device;
     18 
     19 import com.android.ddmlib.AdbCommandRejectedException;
     20 import com.android.ddmlib.AndroidDebugBridge;
     21 import com.android.ddmlib.IDevice;
     22 import com.android.ddmlib.Log;
     23 import com.android.ddmlib.MultiLineReceiver;
     24 import com.android.ddmlib.ShellCommandUnresponsiveException;
     25 import com.android.ddmlib.TimeoutException;
     26 import com.android.hierarchyviewer.scene.VersionLoader;
     27 
     28 import java.io.IOException;
     29 import java.io.File;
     30 import java.util.HashMap;
     31 import java.util.regex.Matcher;
     32 import java.util.regex.Pattern;
     33 
     34 public class DeviceBridge {
     35     private static AndroidDebugBridge bridge;
     36 
     37     private static final HashMap<IDevice, Integer> devicePortMap = new HashMap<IDevice, Integer>();
     38     private static int nextLocalPort = Configuration.DEFAULT_SERVER_PORT;
     39 
     40     public static void initDebugBridge() {
     41         if (bridge == null) {
     42             AndroidDebugBridge.init(false /* debugger support */);
     43         }
     44         if (bridge == null || !bridge.isConnected()) {
     45             String adbLocation = System.getProperty("hierarchyviewer.adb");
     46             if (adbLocation != null && adbLocation.length() != 0) {
     47                 adbLocation += File.separator + "adb";
     48             } else {
     49                 adbLocation = "adb";
     50             }
     51 
     52             bridge = AndroidDebugBridge.createBridge(adbLocation, true);
     53         }
     54     }
     55 
     56     public static void startListenForDevices(AndroidDebugBridge.IDeviceChangeListener listener) {
     57         AndroidDebugBridge.addDeviceChangeListener(listener);
     58     }
     59 
     60     public static IDevice[] getDevices() {
     61         return bridge.getDevices();
     62     }
     63 
     64     public static boolean isViewServerRunning(IDevice device) {
     65         initDebugBridge();
     66         final boolean[] result = new boolean[1];
     67         try {
     68             if (device.isOnline()) {
     69                 device.executeShellCommand(buildIsServerRunningShellCommand(),
     70                         new BooleanResultReader(result));
     71                 if (!result[0]) {
     72                     if (VersionLoader.loadProtocolVersion(device) > 2) {
     73                         result[0] = true;
     74                     }
     75                 }
     76             }
     77         } catch (IOException e) {
     78             e.printStackTrace();
     79         } catch (TimeoutException e) {
     80             e.printStackTrace();
     81         } catch (AdbCommandRejectedException e) {
     82             e.printStackTrace();
     83         } catch (ShellCommandUnresponsiveException e) {
     84             e.printStackTrace();
     85         }
     86         return result[0];
     87     }
     88 
     89     public static boolean startViewServer(IDevice device) {
     90         return startViewServer(device, Configuration.DEFAULT_SERVER_PORT);
     91     }
     92 
     93     public static boolean startViewServer(IDevice device, int port) {
     94         initDebugBridge();
     95         final boolean[] result = new boolean[1];
     96         try {
     97             if (device.isOnline()) {
     98                 device.executeShellCommand(buildStartServerShellCommand(port),
     99                         new BooleanResultReader(result));
    100             }
    101         } catch (IOException e) {
    102             e.printStackTrace();
    103         } catch (TimeoutException e) {
    104             e.printStackTrace();
    105         } catch (AdbCommandRejectedException e) {
    106             e.printStackTrace();
    107         } catch (ShellCommandUnresponsiveException e) {
    108             e.printStackTrace();
    109         }
    110         return result[0];
    111     }
    112 
    113     public static boolean stopViewServer(IDevice device) {
    114         initDebugBridge();
    115         final boolean[] result = new boolean[1];
    116         try {
    117             if (device.isOnline()) {
    118                 device.executeShellCommand(buildStopServerShellCommand(),
    119                         new BooleanResultReader(result));
    120             }
    121         } catch (IOException e) {
    122             e.printStackTrace();
    123         } catch (TimeoutException e) {
    124             e.printStackTrace();
    125         } catch (AdbCommandRejectedException e) {
    126             e.printStackTrace();
    127         } catch (ShellCommandUnresponsiveException e) {
    128             e.printStackTrace();
    129         }
    130         return result[0];
    131     }
    132 
    133     public static void terminate() {
    134         AndroidDebugBridge.terminate();
    135     }
    136 
    137     /**
    138      * Sets up a just-connected device to work with the view server.
    139      * <p/>This starts a port forwarding between a local port and a port on the device.
    140      * @param device
    141      */
    142     public static void setupDeviceForward(IDevice device) {
    143         synchronized (devicePortMap) {
    144             if (device.getState() == IDevice.DeviceState.ONLINE) {
    145                 int localPort = nextLocalPort++;
    146                 try {
    147                     device.createForward(localPort, Configuration.DEFAULT_SERVER_PORT);
    148                     devicePortMap.put(device, localPort);
    149                 } catch (TimeoutException e) {
    150                     Log.e("hierarchy", "Timeout setting up port forwarding for " + device);
    151                 } catch (AdbCommandRejectedException e) {
    152                     Log.e("hierarchy", String.format(
    153                             "Adb rejected forward command for device %1$s: %2$s",
    154                             device, e.getMessage()));
    155                 } catch (IOException e) {
    156                     Log.e("hierarchy", String.format(
    157                             "Failed to create forward for device %1$s: %2$s",
    158                             device, e.getMessage()));
    159                 }
    160             }
    161         }
    162     }
    163 
    164     public static void removeDeviceForward(IDevice device) {
    165         synchronized (devicePortMap) {
    166             final Integer localPort = devicePortMap.get(device);
    167             if (localPort != null) {
    168                 try {
    169                     device.removeForward(localPort, Configuration.DEFAULT_SERVER_PORT);
    170                     devicePortMap.remove(device);
    171                 } catch (TimeoutException e) {
    172                     Log.e("hierarchy", "Timeout removing port forwarding for " + device);
    173                 } catch (AdbCommandRejectedException e) {
    174                     Log.e("hierarchy", String.format(
    175                             "Adb rejected remove-forward command for device %1$s: %2$s",
    176                             device, e.getMessage()));
    177                 } catch (IOException e) {
    178                     Log.e("hierarchy", String.format(
    179                             "Failed to remove forward for device %1$s: %2$s",
    180                             device, e.getMessage()));
    181                 }
    182             }
    183         }
    184     }
    185 
    186     public static int getDeviceLocalPort(IDevice device) {
    187         synchronized (devicePortMap) {
    188             Integer port = devicePortMap.get(device);
    189             if (port != null) {
    190                 return port;
    191             }
    192 
    193             Log.e("hierarchy", "Missing forwarded port for " + device.getSerialNumber());
    194             return -1;
    195         }
    196 
    197     }
    198 
    199     private static String buildStartServerShellCommand(int port) {
    200         return String.format("service call window %d i32 %d",
    201                 Configuration.SERVICE_CODE_START_SERVER, port);
    202     }
    203 
    204     private static String buildStopServerShellCommand() {
    205         return String.format("service call window %d", Configuration.SERVICE_CODE_STOP_SERVER);
    206     }
    207 
    208     private static String buildIsServerRunningShellCommand() {
    209         return String.format("service call window %d",
    210                 Configuration.SERVICE_CODE_IS_SERVER_RUNNING);
    211     }
    212 
    213     private static class BooleanResultReader extends MultiLineReceiver {
    214         private final boolean[] mResult;
    215 
    216         public BooleanResultReader(boolean[] result) {
    217             mResult = result;
    218         }
    219 
    220         @Override
    221         public void processNewLines(String[] strings) {
    222             if (strings.length > 0) {
    223                 Pattern pattern = Pattern.compile(".*?\\([0-9]{8} ([0-9]{8}).*");
    224                 Matcher matcher = pattern.matcher(strings[0]);
    225                 if (matcher.matches()) {
    226                     if (Integer.parseInt(matcher.group(1)) == 1) {
    227                         mResult[0] = true;
    228                     }
    229                 }
    230             }
    231         }
    232 
    233         public boolean isCancelled() {
    234             return false;
    235         }
    236     }
    237 }
    238