aboutsummaryrefslogtreecommitdiff
path: root/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/AMReceiver.java
blob: ea61945a2cbd22c2fef5a1f08f5975ed8ebca8a3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
/*
 * Copyright (C) 2009 The Android Open Source Project
 *
 * Licensed under the Eclipse Public License, Version 1.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.eclipse.org/org/documents/epl-v10.php
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.android.ide.eclipse.adt.internal.launch;

import com.android.ddmlib.IDevice;
import com.android.ddmlib.MultiLineReceiver;
import com.android.ide.eclipse.adt.AdtPlugin;

import java.util.ArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


/**
 * Output receiver for am process (Activity Manager)
 *
 * Monitors adb output for am errors, and retries launch as appropriate.
 */
public class AMReceiver extends MultiLineReceiver {

    private static final int MAX_ATTEMPT_COUNT = 5;
    private static final Pattern sAmErrorType = Pattern.compile("Error type (\\d+)"); //$NON-NLS-1$

    private final DelayedLaunchInfo mLaunchInfo;
    private final IDevice mDevice;
    private final ILaunchController mLaunchController;

    /**
     * Basic constructor.
     *
     * @param launchInfo the {@link DelayedLaunchInfo} associated with the am process.
     * @param device the Android device on which the launch is done.
     * @param launchController the {@link ILaunchController} that is managing the launch
     */
    public AMReceiver(DelayedLaunchInfo launchInfo, IDevice device,
            ILaunchController launchController) {
        mLaunchInfo = launchInfo;
        mDevice = device;
        mLaunchController = launchController;
    }

    /**
     * Monitors the am process for error messages. If an error occurs, will reattempt launch up to
     * <code>MAX_ATTEMPT_COUNT</code> times.
     *
     * @param lines a portion of the am output
     *
     * @see MultiLineReceiver#processNewLines(String[])
     */
    @Override
    public void processNewLines(String[] lines) {
        // first we check if one starts with error
        ArrayList<String> array = new ArrayList<String>();
        boolean error = false;
        boolean warning = false;
        for (String s : lines) {
            // ignore empty lines.
            if (s.length() == 0) {
                continue;
            }

            // check for errors that output an error type, if the attempt count is still
            // valid. If not the whole text will be output in the console
            if (mLaunchInfo.getAttemptCount() < MAX_ATTEMPT_COUNT &&
                    mLaunchInfo.isCancelled() == false) {
                Matcher m = sAmErrorType.matcher(s);
                if (m.matches()) {
                    // get the error type
                    int type = Integer.parseInt(m.group(1));

                    final int waitTime = 3;
                    String msg;

                    switch (type) {
                        case 1:
                            /* Intended fall through */
                        case 2:
                            msg = String.format(
                                    "Device not ready. Waiting %1$d seconds before next attempt.",
                                    waitTime);
                            break;
                        case 3:
                            msg = String.format(
                                    "New package not yet registered with the system. Waiting %1$d seconds before next attempt.",
                                    waitTime);
                            break;
                        default:
                            msg = String.format(
                                    "Device not ready (%2$d). Waiting %1$d seconds before next attempt.",
                                    waitTime, type);
                        break;

                    }

                    AdtPlugin.printToConsole(mLaunchInfo.getProject(), msg);

                    // launch another thread, that waits a bit and attempts another launch
                    new Thread("Delayed Launch attempt") {
                        @Override
                        public void run() {
                            try {
                                sleep(waitTime * 1000);
                            } catch (InterruptedException e) {
                                // ignore
                            }

                            mLaunchController.launchApp(mLaunchInfo, mDevice);
                        }
                    }.start();

                    // no need to parse the rest
                    return;
                }
            }

            // check for error if needed
            if (error == false && s.startsWith("Error:")) { //$NON-NLS-1$
                error = true;
            }
            if (warning == false && s.startsWith("Warning:")) { //$NON-NLS-1$
                warning = true;
            }

            // add the line to the list
            array.add("ActivityManager: " + s); //$NON-NLS-1$
        }

        // then we display them in the console
        if (warning || error) {
            AdtPlugin.printErrorToConsole(mLaunchInfo.getProject(), array.toArray());
        } else {
            AdtPlugin.printToConsole(mLaunchInfo.getProject(), array.toArray());
        }

        // if error then we cancel the launch, and remove the delayed info
        if (error) {
            mLaunchController.stopLaunch(mLaunchInfo);
        }
    }

    /**
     * Returns true if launch has been cancelled
     */
    @Override
    public boolean isCancelled() {
        return mLaunchInfo.isCancelled();
    }
}