OSDN Git Service

original
[gb-231r1-is01/Gingerbread_2.3.3_r1_IS01.git] / sdk / ddms / libs / ddmlib / src / com / android / ddmlib / Device.java
1 /*
2  * Copyright (C) 2007 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.ddmlib;
18
19 import com.android.ddmlib.SyncService.SyncResult;
20 import com.android.ddmlib.log.LogReceiver;
21
22 import java.io.File;
23 import java.io.IOException;
24 import java.nio.channels.SocketChannel;
25 import java.util.ArrayList;
26 import java.util.Collections;
27 import java.util.HashMap;
28 import java.util.List;
29 import java.util.Map;
30 import java.util.regex.Matcher;
31 import java.util.regex.Pattern;
32
33
34 /**
35  * A Device. It can be a physical device or an emulator.
36  */
37 final class Device implements IDevice {
38
39     private final static int INSTALL_TIMEOUT = 2*60*1000; //2min
40
41     /** Emulator Serial Number regexp. */
42     final static String RE_EMULATOR_SN = "emulator-(\\d+)"; //$NON-NLS-1$
43
44     /** Serial number of the device */
45     private String mSerialNumber = null;
46
47     /** Name of the AVD */
48     private String mAvdName = null;
49
50     /** State of the device. */
51     private DeviceState mState = null;
52
53     /** Device properties. */
54     private final Map<String, String> mProperties = new HashMap<String, String>();
55     private final Map<String, String> mMountPoints = new HashMap<String, String>();
56
57     private final ArrayList<Client> mClients = new ArrayList<Client>();
58     private DeviceMonitor mMonitor;
59
60     private static final String LOG_TAG = "Device";
61
62     /**
63      * Socket for the connection monitoring client connection/disconnection.
64      */
65     private SocketChannel mSocketChannel;
66
67     /**
68      * Output receiver for "pm install package.apk" command line.
69      */
70     private static final class InstallReceiver extends MultiLineReceiver {
71
72         private static final String SUCCESS_OUTPUT = "Success"; //$NON-NLS-1$
73         private static final Pattern FAILURE_PATTERN = Pattern.compile("Failure\\s+\\[(.*)\\]"); //$NON-NLS-1$
74
75         private String mErrorMessage = null;
76
77         public InstallReceiver() {
78         }
79
80         @Override
81         public void processNewLines(String[] lines) {
82             for (String line : lines) {
83                 if (line.length() > 0) {
84                     if (line.startsWith(SUCCESS_OUTPUT)) {
85                         mErrorMessage = null;
86                     } else {
87                         Matcher m = FAILURE_PATTERN.matcher(line);
88                         if (m.matches()) {
89                             mErrorMessage = m.group(1);
90                         }
91                     }
92                 }
93             }
94         }
95
96         public boolean isCancelled() {
97             return false;
98         }
99
100         public String getErrorMessage() {
101             return mErrorMessage;
102         }
103     }
104
105     /*
106      * (non-Javadoc)
107      * @see com.android.ddmlib.IDevice#getSerialNumber()
108      */
109     public String getSerialNumber() {
110         return mSerialNumber;
111     }
112
113     /** {@inheritDoc} */
114     public String getAvdName() {
115         return mAvdName;
116     }
117
118     /**
119      * Sets the name of the AVD
120      */
121     void setAvdName(String avdName) {
122         if (isEmulator() == false) {
123             throw new IllegalArgumentException(
124                     "Cannot set the AVD name of the device is not an emulator");
125         }
126
127         mAvdName = avdName;
128     }
129
130     /*
131      * (non-Javadoc)
132      * @see com.android.ddmlib.IDevice#getState()
133      */
134     public DeviceState getState() {
135         return mState;
136     }
137
138     /**
139      * Changes the state of the device.
140      */
141     void setState(DeviceState state) {
142         mState = state;
143     }
144
145
146     /*
147      * (non-Javadoc)
148      * @see com.android.ddmlib.IDevice#getProperties()
149      */
150     public Map<String, String> getProperties() {
151         return Collections.unmodifiableMap(mProperties);
152     }
153
154     /*
155      * (non-Javadoc)
156      * @see com.android.ddmlib.IDevice#getPropertyCount()
157      */
158     public int getPropertyCount() {
159         return mProperties.size();
160     }
161
162     /*
163      * (non-Javadoc)
164      * @see com.android.ddmlib.IDevice#getProperty(java.lang.String)
165      */
166     public String getProperty(String name) {
167         return mProperties.get(name);
168     }
169
170     public String getMountPoint(String name) {
171         return mMountPoints.get(name);
172     }
173
174
175     @Override
176     public String toString() {
177         return mSerialNumber;
178     }
179
180     /*
181      * (non-Javadoc)
182      * @see com.android.ddmlib.IDevice#isOnline()
183      */
184     public boolean isOnline() {
185         return mState == DeviceState.ONLINE;
186     }
187
188     /*
189      * (non-Javadoc)
190      * @see com.android.ddmlib.IDevice#isEmulator()
191      */
192     public boolean isEmulator() {
193         return mSerialNumber.matches(RE_EMULATOR_SN);
194     }
195
196     /*
197      * (non-Javadoc)
198      * @see com.android.ddmlib.IDevice#isOffline()
199      */
200     public boolean isOffline() {
201         return mState == DeviceState.OFFLINE;
202     }
203
204     /*
205      * (non-Javadoc)
206      * @see com.android.ddmlib.IDevice#isBootLoader()
207      */
208     public boolean isBootLoader() {
209         return mState == DeviceState.BOOTLOADER;
210     }
211
212     /*
213      * (non-Javadoc)
214      * @see com.android.ddmlib.IDevice#hasClients()
215      */
216     public boolean hasClients() {
217         return mClients.size() > 0;
218     }
219
220     /*
221      * (non-Javadoc)
222      * @see com.android.ddmlib.IDevice#getClients()
223      */
224     public Client[] getClients() {
225         synchronized (mClients) {
226             return mClients.toArray(new Client[mClients.size()]);
227         }
228     }
229
230     /*
231      * (non-Javadoc)
232      * @see com.android.ddmlib.IDevice#getClient(java.lang.String)
233      */
234     public Client getClient(String applicationName) {
235         synchronized (mClients) {
236             for (Client c : mClients) {
237                 if (applicationName.equals(c.getClientData().getClientDescription())) {
238                     return c;
239                 }
240             }
241
242         }
243
244         return null;
245     }
246
247     /*
248      * (non-Javadoc)
249      * @see com.android.ddmlib.IDevice#getSyncService()
250      */
251     public SyncService getSyncService()
252             throws TimeoutException, AdbCommandRejectedException, IOException {
253         SyncService syncService = new SyncService(AndroidDebugBridge.getSocketAddress(), this);
254         if (syncService.openSync()) {
255             return syncService;
256          }
257
258         return null;
259     }
260
261     /*
262      * (non-Javadoc)
263      * @see com.android.ddmlib.IDevice#getFileListingService()
264      */
265     public FileListingService getFileListingService() {
266         return new FileListingService(this);
267     }
268
269     public RawImage getScreenshot()
270             throws TimeoutException, AdbCommandRejectedException, IOException {
271         return AdbHelper.getFrameBuffer(AndroidDebugBridge.getSocketAddress(), this);
272     }
273
274     public void executeShellCommand(String command, IShellOutputReceiver receiver)
275             throws TimeoutException, AdbCommandRejectedException, ShellCommandUnresponsiveException,
276             IOException {
277         AdbHelper.executeRemoteCommand(AndroidDebugBridge.getSocketAddress(), command, this,
278                 receiver, DdmPreferences.getTimeOut());
279     }
280
281     public void executeShellCommand(String command, IShellOutputReceiver receiver,
282             int maxTimeToOutputResponse)
283             throws TimeoutException, AdbCommandRejectedException, ShellCommandUnresponsiveException,
284             IOException {
285         AdbHelper.executeRemoteCommand(AndroidDebugBridge.getSocketAddress(), command, this,
286                 receiver, maxTimeToOutputResponse);
287     }
288
289     public void runEventLogService(LogReceiver receiver)
290             throws TimeoutException, AdbCommandRejectedException, IOException {
291         AdbHelper.runEventLogService(AndroidDebugBridge.getSocketAddress(), this, receiver);
292     }
293
294     public void runLogService(String logname, LogReceiver receiver)
295             throws TimeoutException, AdbCommandRejectedException, IOException {
296         AdbHelper.runLogService(AndroidDebugBridge.getSocketAddress(), this, logname, receiver);
297     }
298
299     public void createForward(int localPort, int remotePort)
300             throws TimeoutException, AdbCommandRejectedException, IOException {
301         AdbHelper.createForward(AndroidDebugBridge.getSocketAddress(), this, localPort, remotePort);
302     }
303
304     public void removeForward(int localPort, int remotePort)
305             throws TimeoutException, AdbCommandRejectedException, IOException {
306         AdbHelper.removeForward(AndroidDebugBridge.getSocketAddress(), this, localPort, remotePort);
307     }
308
309     /*
310      * (non-Javadoc)
311      * @see com.android.ddmlib.IDevice#getClientName(int)
312      */
313     public String getClientName(int pid) {
314         synchronized (mClients) {
315             for (Client c : mClients) {
316                 if (c.getClientData().getPid() == pid) {
317                     return c.getClientData().getClientDescription();
318                 }
319             }
320         }
321
322         return null;
323     }
324
325
326     Device(DeviceMonitor monitor, String serialNumber, DeviceState deviceState) {
327         mMonitor = monitor;
328         mSerialNumber = serialNumber;
329         mState = deviceState;
330     }
331
332     DeviceMonitor getMonitor() {
333         return mMonitor;
334     }
335
336     void addClient(Client client) {
337         synchronized (mClients) {
338             mClients.add(client);
339         }
340     }
341
342     List<Client> getClientList() {
343         return mClients;
344     }
345
346     boolean hasClient(int pid) {
347         synchronized (mClients) {
348             for (Client client : mClients) {
349                 if (client.getClientData().getPid() == pid) {
350                     return true;
351                 }
352             }
353         }
354
355         return false;
356     }
357
358     void clearClientList() {
359         synchronized (mClients) {
360             mClients.clear();
361         }
362     }
363
364     /**
365      * Sets the client monitoring socket.
366      * @param socketChannel the sockets
367      */
368     void setClientMonitoringSocket(SocketChannel socketChannel) {
369         mSocketChannel = socketChannel;
370     }
371
372     /**
373      * Returns the client monitoring socket.
374      */
375     SocketChannel getClientMonitoringSocket() {
376         return mSocketChannel;
377     }
378
379     /**
380      * Removes a {@link Client} from the list.
381      * @param client the client to remove.
382      * @param notify Whether or not to notify the listeners of a change.
383      */
384     void removeClient(Client client, boolean notify) {
385         mMonitor.addPortToAvailableList(client.getDebuggerListenPort());
386         synchronized (mClients) {
387             mClients.remove(client);
388         }
389         if (notify) {
390             mMonitor.getServer().deviceChanged(this, CHANGE_CLIENT_LIST);
391         }
392     }
393
394     void update(int changeMask) {
395         mMonitor.getServer().deviceChanged(this, changeMask);
396     }
397
398     void update(Client client, int changeMask) {
399         mMonitor.getServer().clientChanged(client, changeMask);
400     }
401
402     void addProperty(String label, String value) {
403         mProperties.put(label, value);
404     }
405
406     void setMountingPoint(String name, String value) {
407         mMountPoints.put(name, value);
408     }
409
410     public String installPackage(String packageFilePath, boolean reinstall)
411            throws TimeoutException, AdbCommandRejectedException, ShellCommandUnresponsiveException,
412            IOException {
413        String remoteFilePath = syncPackageToDevice(packageFilePath);
414        String result = installRemotePackage(remoteFilePath, reinstall);
415        removeRemotePackage(remoteFilePath);
416        return result;
417     }
418
419     public String syncPackageToDevice(String localFilePath)
420             throws IOException, AdbCommandRejectedException, TimeoutException {
421         try {
422             String packageFileName = getFileName(localFilePath);
423             String remoteFilePath = String.format("/data/local/tmp/%1$s", packageFileName); //$NON-NLS-1$
424
425             Log.d(packageFileName, String.format("Uploading %1$s onto device '%2$s'",
426                     packageFileName, getSerialNumber()));
427
428             SyncService sync = getSyncService();
429             if (sync != null) {
430                 String message = String.format("Uploading file onto device '%1$s'",
431                         getSerialNumber());
432                 Log.d(LOG_TAG, message);
433                 SyncResult result = sync.pushFile(localFilePath, remoteFilePath,
434                         SyncService.getNullProgressMonitor());
435
436                 if (result.getCode() != SyncService.RESULT_OK) {
437                     throw new IOException(String.format("Unable to upload file: %1$s",
438                             result.getMessage()));
439                 }
440             } else {
441                 throw new IOException("Unable to open sync connection!");
442             }
443             return remoteFilePath;
444         } catch (TimeoutException e) {
445             Log.e(LOG_TAG, "Unable to open sync connection! Timeout.");
446             throw e;
447         } catch (IOException e) {
448             Log.e(LOG_TAG, String.format("Unable to open sync connection! reason: %1$s",
449                     e.getMessage()));
450             throw e;
451         }
452     }
453
454     /**
455      * Helper method to retrieve the file name given a local file path
456      * @param filePath full directory path to file
457      * @return {@link String} file name
458      */
459     private String getFileName(String filePath) {
460         return new File(filePath).getName();
461     }
462
463     public String installRemotePackage(String remoteFilePath, boolean reinstall)
464             throws TimeoutException, AdbCommandRejectedException, ShellCommandUnresponsiveException,
465             IOException {
466         InstallReceiver receiver = new InstallReceiver();
467         String cmd = String.format(reinstall ? "pm install -r \"%1$s\"" : "pm install \"%1$s\"",
468                             remoteFilePath);
469         executeShellCommand(cmd, receiver, INSTALL_TIMEOUT);
470         return receiver.getErrorMessage();
471     }
472
473     /**
474      * {@inheritDoc}
475      */
476     public void removeRemotePackage(String remoteFilePath)
477             throws TimeoutException, AdbCommandRejectedException, ShellCommandUnresponsiveException,
478             IOException {
479         // now we delete the app we sync'ed
480         try {
481             executeShellCommand("rm " + remoteFilePath, new NullOutputReceiver(), INSTALL_TIMEOUT);
482         } catch (IOException e) {
483             Log.e(LOG_TAG, String.format("Failed to delete temporary package: %1$s",
484                     e.getMessage()));
485             throw e;
486         }
487     }
488
489     /**
490      * {@inheritDoc}
491      */
492     public String uninstallPackage(String packageName)
493             throws TimeoutException, AdbCommandRejectedException, ShellCommandUnresponsiveException,
494             IOException {
495         InstallReceiver receiver = new InstallReceiver();
496         executeShellCommand("pm uninstall " + packageName, receiver, INSTALL_TIMEOUT);
497         return receiver.getErrorMessage();
498     }
499
500     /*
501      * (non-Javadoc)
502      * @see com.android.ddmlib.IDevice#reboot()
503      */
504     public void reboot(String into)
505             throws TimeoutException, AdbCommandRejectedException, IOException {
506         AdbHelper.reboot(into, AndroidDebugBridge.getSocketAddress(), this);
507     }
508 }