Home | History | Annotate | Download | only in launch
      1 /*
      2  * Copyright (C) 2009 The Android Open Source Project
      3  *
      4  * Licensed under the Eclipse Public License, Version 1.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.eclipse.org/org/documents/epl-v10.php
      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 package com.android.ide.eclipse.adt.internal.launch;
     17 
     18 import com.android.ddmlib.IDevice;
     19 import com.android.ddmlib.MultiLineReceiver;
     20 import com.android.ide.eclipse.adt.AdtPlugin;
     21 
     22 import java.util.ArrayList;
     23 import java.util.regex.Matcher;
     24 import java.util.regex.Pattern;
     25 
     26 
     27 /**
     28  * Output receiver for am process (Activity Manager)
     29  *
     30  * Monitors adb output for am errors, and retries launch as appropriate.
     31  */
     32 public class AMReceiver extends MultiLineReceiver {
     33 
     34     private static final int MAX_ATTEMPT_COUNT = 5;
     35     private static final Pattern sAmErrorType = Pattern.compile("Error type (\\d+)"); //$NON-NLS-1$
     36 
     37     private final DelayedLaunchInfo mLaunchInfo;
     38     private final IDevice mDevice;
     39     private final ILaunchController mLaunchController;
     40 
     41     /**
     42      * Basic constructor.
     43      *
     44      * @param launchInfo the {@link DelayedLaunchInfo} associated with the am process.
     45      * @param device the Android device on which the launch is done.
     46      * @param launchController the {@link ILaunchController} that is managing the launch
     47      */
     48     public AMReceiver(DelayedLaunchInfo launchInfo, IDevice device,
     49             ILaunchController launchController) {
     50         mLaunchInfo = launchInfo;
     51         mDevice = device;
     52         mLaunchController = launchController;
     53     }
     54 
     55     /**
     56      * Monitors the am process for error messages. If an error occurs, will reattempt launch up to
     57      * <code>MAX_ATTEMPT_COUNT</code> times.
     58      *
     59      * @param lines a portion of the am output
     60      *
     61      * @see MultiLineReceiver#processNewLines(String[])
     62      */
     63     @Override
     64     public void processNewLines(String[] lines) {
     65         // first we check if one starts with error
     66         ArrayList<String> array = new ArrayList<String>();
     67         boolean error = false;
     68         boolean warning = false;
     69         for (String s : lines) {
     70             // ignore empty lines.
     71             if (s.length() == 0) {
     72                 continue;
     73             }
     74 
     75             // check for errors that output an error type, if the attempt count is still
     76             // valid. If not the whole text will be output in the console
     77             if (mLaunchInfo.getAttemptCount() < MAX_ATTEMPT_COUNT &&
     78                     mLaunchInfo.isCancelled() == false) {
     79                 Matcher m = sAmErrorType.matcher(s);
     80                 if (m.matches()) {
     81                     // get the error type
     82                     int type = Integer.parseInt(m.group(1));
     83 
     84                     final int waitTime = 3;
     85                     String msg;
     86 
     87                     switch (type) {
     88                         case 1:
     89                             /* Intended fall through */
     90                         case 2:
     91                             msg = String.format(
     92                                     "Device not ready. Waiting %1$d seconds before next attempt.",
     93                                     waitTime);
     94                             break;
     95                         case 3:
     96                             msg = String.format(
     97                                     "New package not yet registered with the system. Waiting %1$d seconds before next attempt.",
     98                                     waitTime);
     99                             break;
    100                         default:
    101                             msg = String.format(
    102                                     "Device not ready (%2$d). Waiting %1$d seconds before next attempt.",
    103                                     waitTime, type);
    104                         break;
    105 
    106                     }
    107 
    108                     AdtPlugin.printToConsole(mLaunchInfo.getProject(), msg);
    109 
    110                     // launch another thread, that waits a bit and attempts another launch
    111                     new Thread("Delayed Launch attempt") {
    112                         @Override
    113                         public void run() {
    114                             try {
    115                                 sleep(waitTime * 1000);
    116                             } catch (InterruptedException e) {
    117                                 // ignore
    118                             }
    119 
    120                             mLaunchController.launchApp(mLaunchInfo, mDevice);
    121                         }
    122                     }.start();
    123 
    124                     // no need to parse the rest
    125                     return;
    126                 }
    127             }
    128 
    129             // check for error if needed
    130             if (error == false && s.startsWith("Error:")) { //$NON-NLS-1$
    131                 error = true;
    132             }
    133             if (warning == false && s.startsWith("Warning:")) { //$NON-NLS-1$
    134                 warning = true;
    135             }
    136 
    137             // add the line to the list
    138             array.add("ActivityManager: " + s); //$NON-NLS-1$
    139         }
    140 
    141         // then we display them in the console
    142         if (warning || error) {
    143             AdtPlugin.printErrorToConsole(mLaunchInfo.getProject(), array.toArray());
    144         } else {
    145             AdtPlugin.printToConsole(mLaunchInfo.getProject(), array.toArray());
    146         }
    147 
    148         // if error then we cancel the launch, and remove the delayed info
    149         if (error) {
    150             mLaunchController.stopLaunch(mLaunchInfo);
    151         }
    152     }
    153 
    154     /**
    155      * Returns true if launch has been cancelled
    156      */
    157     @Override
    158     public boolean isCancelled() {
    159         return mLaunchInfo.isCancelled();
    160     }
    161 }
    162