129564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath/*
229564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath * Copyright (C) 2008 The Android Open Source Project
329564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath *
429564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath * Licensed under the Apache License, Version 2.0 (the "License");
529564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath * you may not use this file except in compliance with the License.
629564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath * You may obtain a copy of the License at
729564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath *
829564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath *      http://www.apache.org/licenses/LICENSE-2.0
929564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath *
1029564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath * Unless required by applicable law or agreed to in writing, software
1129564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath * distributed under the License is distributed on an "AS IS" BASIS,
1229564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1329564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath * See the License for the specific language governing permissions and
1429564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath * limitations under the License
1529564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath */
1629564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath
1729564cd24589867f653cd22cabbaac6493cfc530Narayan Kamathpackage com.android.internal.os;
1829564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath
1929564cd24589867f653cd22cabbaac6493cfc530Narayan Kamathimport android.net.LocalSocket;
2029564cd24589867f653cd22cabbaac6493cfc530Narayan Kamathimport android.net.LocalSocketAddress;
21c8a2cfed0192afc6a408f4bdb77e8a0bdd5d752bMakoto Onukiimport android.os.SystemClock;
22fdeeeea6cfdebdb98dd70a7dd48965743af01750Jeff Sharkeyimport android.text.TextUtils;
2329564cd24589867f653cd22cabbaac6493cfc530Narayan Kamathimport android.util.Slog;
24fa54ab7950b7ad7605cb842b47826b71a685bc28Todd Kennedy
258948c01eb726ec79983472e5597ddac8004f9f44Jeff Sharkeyimport com.android.internal.util.Preconditions;
268948c01eb726ec79983472e5597ddac8004f9f44Jeff Sharkey
2729564cd24589867f653cd22cabbaac6493cfc530Narayan Kamathimport libcore.io.IoUtils;
2829564cd24589867f653cd22cabbaac6493cfc530Narayan Kamathimport libcore.io.Streams;
2929564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath
3029564cd24589867f653cd22cabbaac6493cfc530Narayan Kamathimport java.io.IOException;
3129564cd24589867f653cd22cabbaac6493cfc530Narayan Kamathimport java.io.InputStream;
3229564cd24589867f653cd22cabbaac6493cfc530Narayan Kamathimport java.io.OutputStream;
33fdeeeea6cfdebdb98dd70a7dd48965743af01750Jeff Sharkeyimport java.util.Arrays;
3429564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath
3529564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath/**
3629564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath * Represents a connection to {@code installd}. Allows multiple connect and
3729564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath * disconnect cycles.
3829564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath *
3929564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath * @hide for internal use only
4029564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath */
4129564cd24589867f653cd22cabbaac6493cfc530Narayan Kamathpublic class InstallerConnection {
4229564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath    private static final String TAG = "InstallerConnection";
4329564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath    private static final boolean LOCAL_DEBUG = false;
4429564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath
4529564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath    private InputStream mIn;
4629564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath    private OutputStream mOut;
4729564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath    private LocalSocket mSocket;
4829564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath
498948c01eb726ec79983472e5597ddac8004f9f44Jeff Sharkey    private volatile Object mWarnIfHeld;
508948c01eb726ec79983472e5597ddac8004f9f44Jeff Sharkey
5129564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath    private final byte buf[] = new byte[1024];
5229564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath
5329564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath    public InstallerConnection() {
5429564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath    }
5529564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath
568948c01eb726ec79983472e5597ddac8004f9f44Jeff Sharkey    /**
578948c01eb726ec79983472e5597ddac8004f9f44Jeff Sharkey     * Yell loudly if someone tries making future calls while holding a lock on
588948c01eb726ec79983472e5597ddac8004f9f44Jeff Sharkey     * the given object.
598948c01eb726ec79983472e5597ddac8004f9f44Jeff Sharkey     */
608948c01eb726ec79983472e5597ddac8004f9f44Jeff Sharkey    public void setWarnIfHeld(Object warnIfHeld) {
618948c01eb726ec79983472e5597ddac8004f9f44Jeff Sharkey        Preconditions.checkState(mWarnIfHeld == null);
628948c01eb726ec79983472e5597ddac8004f9f44Jeff Sharkey        mWarnIfHeld = Preconditions.checkNotNull(warnIfHeld);
638948c01eb726ec79983472e5597ddac8004f9f44Jeff Sharkey    }
648948c01eb726ec79983472e5597ddac8004f9f44Jeff Sharkey
6529564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath    public synchronized String transact(String cmd) {
66fdeeeea6cfdebdb98dd70a7dd48965743af01750Jeff Sharkey        if (mWarnIfHeld != null && Thread.holdsLock(mWarnIfHeld)) {
67fdeeeea6cfdebdb98dd70a7dd48965743af01750Jeff Sharkey            Slog.wtf(TAG, "Calling thread " + Thread.currentThread().getName() + " is holding 0x"
68fdeeeea6cfdebdb98dd70a7dd48965743af01750Jeff Sharkey                    + Integer.toHexString(System.identityHashCode(mWarnIfHeld)), new Throwable());
69fdeeeea6cfdebdb98dd70a7dd48965743af01750Jeff Sharkey        }
70fdeeeea6cfdebdb98dd70a7dd48965743af01750Jeff Sharkey
7129564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        if (!connect()) {
7229564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath            Slog.e(TAG, "connection failed");
7329564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath            return "-1";
7429564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        }
7529564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath
7629564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        if (!writeCommand(cmd)) {
7729564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath            /*
7829564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath             * If installd died and restarted in the background (unlikely but
7929564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath             * possible) we'll fail on the next write (this one). Try to
8029564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath             * reconnect and write the command one more time before giving up.
8129564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath             */
8229564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath            Slog.e(TAG, "write command failed? reconnect!");
8329564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath            if (!connect() || !writeCommand(cmd)) {
8429564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath                return "-1";
8529564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath            }
8629564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        }
8729564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        if (LOCAL_DEBUG) {
8829564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath            Slog.i(TAG, "send: '" + cmd + "'");
8929564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        }
9029564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath
9129564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        final int replyLength = readReply();
9229564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        if (replyLength > 0) {
9329564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath            String s = new String(buf, 0, replyLength);
9429564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath            if (LOCAL_DEBUG) {
9529564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath                Slog.i(TAG, "recv: '" + s + "'");
9629564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath            }
9729564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath            return s;
9829564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        } else {
9929564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath            if (LOCAL_DEBUG) {
10029564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath                Slog.i(TAG, "fail");
10129564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath            }
10229564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath            return "-1";
10329564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        }
10429564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath    }
10529564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath
1064288419787120ce85a241a4b315d7d2123aa2d4aJeff Sharkey    public String[] execute(String cmd, Object... args) throws InstallerException {
107fdeeeea6cfdebdb98dd70a7dd48965743af01750Jeff Sharkey        final StringBuilder builder = new StringBuilder(cmd);
108fdeeeea6cfdebdb98dd70a7dd48965743af01750Jeff Sharkey        for (Object arg : args) {
109fdeeeea6cfdebdb98dd70a7dd48965743af01750Jeff Sharkey            String escaped;
110fdeeeea6cfdebdb98dd70a7dd48965743af01750Jeff Sharkey            if (arg == null) {
111fdeeeea6cfdebdb98dd70a7dd48965743af01750Jeff Sharkey                escaped = "";
112fdeeeea6cfdebdb98dd70a7dd48965743af01750Jeff Sharkey            } else {
113fdeeeea6cfdebdb98dd70a7dd48965743af01750Jeff Sharkey                escaped = String.valueOf(arg);
114fdeeeea6cfdebdb98dd70a7dd48965743af01750Jeff Sharkey            }
115fdeeeea6cfdebdb98dd70a7dd48965743af01750Jeff Sharkey            if (escaped.indexOf('\0') != -1 || escaped.indexOf(' ') != -1 || "!".equals(escaped)) {
116fdeeeea6cfdebdb98dd70a7dd48965743af01750Jeff Sharkey                throw new InstallerException(
117fdeeeea6cfdebdb98dd70a7dd48965743af01750Jeff Sharkey                        "Invalid argument while executing " + cmd + " " + Arrays.toString(args));
118fdeeeea6cfdebdb98dd70a7dd48965743af01750Jeff Sharkey            }
119fdeeeea6cfdebdb98dd70a7dd48965743af01750Jeff Sharkey            if (TextUtils.isEmpty(escaped)) {
120fdeeeea6cfdebdb98dd70a7dd48965743af01750Jeff Sharkey                escaped = "!";
121fdeeeea6cfdebdb98dd70a7dd48965743af01750Jeff Sharkey            }
122fdeeeea6cfdebdb98dd70a7dd48965743af01750Jeff Sharkey            builder.append(' ').append(escaped);
12329564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        }
1244288419787120ce85a241a4b315d7d2123aa2d4aJeff Sharkey        final String[] resRaw = transact(builder.toString()).split(" ");
1254288419787120ce85a241a4b315d7d2123aa2d4aJeff Sharkey        int res = -1;
1264288419787120ce85a241a4b315d7d2123aa2d4aJeff Sharkey        try {
1274288419787120ce85a241a4b315d7d2123aa2d4aJeff Sharkey            res = Integer.parseInt(resRaw[0]);
1284288419787120ce85a241a4b315d7d2123aa2d4aJeff Sharkey        } catch (ArrayIndexOutOfBoundsException | NumberFormatException ignored) {
1294288419787120ce85a241a4b315d7d2123aa2d4aJeff Sharkey        }
1304288419787120ce85a241a4b315d7d2123aa2d4aJeff Sharkey        if (res != 0) {
1314288419787120ce85a241a4b315d7d2123aa2d4aJeff Sharkey            throw new InstallerException(
1324288419787120ce85a241a4b315d7d2123aa2d4aJeff Sharkey                    "Failed to execute " + cmd + " " + Arrays.toString(args) + ": " + res);
1334288419787120ce85a241a4b315d7d2123aa2d4aJeff Sharkey        }
1344288419787120ce85a241a4b315d7d2123aa2d4aJeff Sharkey        return resRaw;
13529564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath    }
13629564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath
137fdeeeea6cfdebdb98dd70a7dd48965743af01750Jeff Sharkey    public void dexopt(String apkPath, int uid, String instructionSet, int dexoptNeeded,
138c7b9482b0c4bb2d378e63541b96be45c50094e05Jeff Hao            int dexFlags, String compilerFilter, String volumeUuid, String sharedLibraries)
139c7b9482b0c4bb2d378e63541b96be45c50094e05Jeff Hao            throws InstallerException {
140c7b9482b0c4bb2d378e63541b96be45c50094e05Jeff Hao        dexopt(apkPath, uid, "*", instructionSet, dexoptNeeded, null /*outputPath*/, dexFlags,
141c7b9482b0c4bb2d378e63541b96be45c50094e05Jeff Hao                compilerFilter, volumeUuid, sharedLibraries);
142feb193085adbdc379ee70dbb7dc6ae4c9f2971ddCalin Juravle    }
143feb193085adbdc379ee70dbb7dc6ae4c9f2971ddCalin Juravle
144fdeeeea6cfdebdb98dd70a7dd48965743af01750Jeff Sharkey    public void dexopt(String apkPath, int uid, String pkgName, String instructionSet,
145bdd30d86ef98456161069d11481b2ccd25a11b4eAndreas Gampe            int dexoptNeeded, String outputPath, int dexFlags, String compilerFilter,
146c7b9482b0c4bb2d378e63541b96be45c50094e05Jeff Hao            String volumeUuid, String sharedLibraries) throws InstallerException {
147db4a79a5d7d348e9d2286d95d4e5a59dd484456fCalin Juravle        execute("dexopt",
148db4a79a5d7d348e9d2286d95d4e5a59dd484456fCalin Juravle                apkPath,
149db4a79a5d7d348e9d2286d95d4e5a59dd484456fCalin Juravle                uid,
150db4a79a5d7d348e9d2286d95d4e5a59dd484456fCalin Juravle                pkgName,
151db4a79a5d7d348e9d2286d95d4e5a59dd484456fCalin Juravle                instructionSet,
152db4a79a5d7d348e9d2286d95d4e5a59dd484456fCalin Juravle                dexoptNeeded,
153db4a79a5d7d348e9d2286d95d4e5a59dd484456fCalin Juravle                outputPath,
154db4a79a5d7d348e9d2286d95d4e5a59dd484456fCalin Juravle                dexFlags,
155bdd30d86ef98456161069d11481b2ccd25a11b4eAndreas Gampe                compilerFilter,
156c7b9482b0c4bb2d378e63541b96be45c50094e05Jeff Hao                volumeUuid,
157c7b9482b0c4bb2d378e63541b96be45c50094e05Jeff Hao                sharedLibraries);
158bdd30d86ef98456161069d11481b2ccd25a11b4eAndreas Gampe    }
159bdd30d86ef98456161069d11481b2ccd25a11b4eAndreas Gampe
160a87770828637813dacd176ba3c8d3810f7ed6ab8David Sehr    private boolean safeParseBooleanResult(String[] res) throws InstallerException {
161bdd30d86ef98456161069d11481b2ccd25a11b4eAndreas Gampe        if ((res == null) || (res.length != 2)) {
1624288419787120ce85a241a4b315d7d2123aa2d4aJeff Sharkey            throw new InstallerException("Invalid size result: " + Arrays.toString(res));
163bdd30d86ef98456161069d11481b2ccd25a11b4eAndreas Gampe        }
164bdd30d86ef98456161069d11481b2ccd25a11b4eAndreas Gampe
165bdd30d86ef98456161069d11481b2ccd25a11b4eAndreas Gampe        // Just as a sanity check. Anything != "true" will be interpreted as false by parseBoolean.
166bdd30d86ef98456161069d11481b2ccd25a11b4eAndreas Gampe        if (!res[1].equals("true") && !res[1].equals("false")) {
1674288419787120ce85a241a4b315d7d2123aa2d4aJeff Sharkey            throw new InstallerException("Invalid boolean result: " + Arrays.toString(res));
168bdd30d86ef98456161069d11481b2ccd25a11b4eAndreas Gampe        }
169bdd30d86ef98456161069d11481b2ccd25a11b4eAndreas Gampe
170bdd30d86ef98456161069d11481b2ccd25a11b4eAndreas Gampe        return Boolean.parseBoolean(res[1]);
17129564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath    }
17229564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath
173a87770828637813dacd176ba3c8d3810f7ed6ab8David Sehr    public boolean mergeProfiles(int uid, String pkgName) throws InstallerException {
174a87770828637813dacd176ba3c8d3810f7ed6ab8David Sehr        final String[] res = execute("merge_profiles", uid, pkgName);
175a87770828637813dacd176ba3c8d3810f7ed6ab8David Sehr
176a87770828637813dacd176ba3c8d3810f7ed6ab8David Sehr        return safeParseBooleanResult(res);
177a87770828637813dacd176ba3c8d3810f7ed6ab8David Sehr    }
178a87770828637813dacd176ba3c8d3810f7ed6ab8David Sehr
179a87770828637813dacd176ba3c8d3810f7ed6ab8David Sehr    public boolean dumpProfiles(String gid, String packageName, String codePaths)
180a87770828637813dacd176ba3c8d3810f7ed6ab8David Sehr            throws InstallerException {
181a87770828637813dacd176ba3c8d3810f7ed6ab8David Sehr        final String[] res = execute("dump_profiles", gid, packageName, codePaths);
182a87770828637813dacd176ba3c8d3810f7ed6ab8David Sehr
183a87770828637813dacd176ba3c8d3810f7ed6ab8David Sehr        return safeParseBooleanResult(res);
184a87770828637813dacd176ba3c8d3810f7ed6ab8David Sehr    }
185a87770828637813dacd176ba3c8d3810f7ed6ab8David Sehr
18629564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath    private boolean connect() {
18729564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        if (mSocket != null) {
18829564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath            return true;
18929564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        }
19029564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        Slog.i(TAG, "connecting...");
19129564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        try {
19229564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath            mSocket = new LocalSocket();
19329564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath
19429564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath            LocalSocketAddress address = new LocalSocketAddress("installd",
19529564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath                    LocalSocketAddress.Namespace.RESERVED);
19629564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath
19729564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath            mSocket.connect(address);
19829564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath
19929564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath            mIn = mSocket.getInputStream();
20029564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath            mOut = mSocket.getOutputStream();
20129564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        } catch (IOException ex) {
20229564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath            disconnect();
20329564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath            return false;
20429564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        }
20529564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        return true;
20629564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath    }
20729564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath
20829564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath    public void disconnect() {
20929564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        Slog.i(TAG, "disconnecting...");
21029564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        IoUtils.closeQuietly(mSocket);
21129564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        IoUtils.closeQuietly(mIn);
21229564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        IoUtils.closeQuietly(mOut);
21329564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath
21429564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        mSocket = null;
21529564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        mIn = null;
21629564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        mOut = null;
21729564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath    }
21829564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath
21929564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath
22029564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath    private boolean readFully(byte[] buffer, int len) {
22129564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        try {
22229564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath            Streams.readFully(mIn, buffer, 0, len);
22329564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        } catch (IOException ioe) {
22429564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath            Slog.e(TAG, "read exception");
22529564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath            disconnect();
22629564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath            return false;
22729564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        }
22829564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath
22929564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        if (LOCAL_DEBUG) {
23029564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath            Slog.i(TAG, "read " + len + " bytes");
23129564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        }
23229564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath
23329564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        return true;
23429564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath    }
23529564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath
23629564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath    private int readReply() {
23729564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        if (!readFully(buf, 2)) {
23829564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath            return -1;
23929564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        }
24029564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath
24129564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        final int len = (((int) buf[0]) & 0xff) | ((((int) buf[1]) & 0xff) << 8);
24229564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        if ((len < 1) || (len > buf.length)) {
24329564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath            Slog.e(TAG, "invalid reply length (" + len + ")");
24429564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath            disconnect();
24529564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath            return -1;
24629564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        }
24729564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath
24829564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        if (!readFully(buf, len)) {
24929564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath            return -1;
25029564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        }
25129564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath
25229564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        return len;
25329564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath    }
25429564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath
25529564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath    private boolean writeCommand(String cmdString) {
25629564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        final byte[] cmd = cmdString.getBytes();
25729564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        final int len = cmd.length;
25829564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        if ((len < 1) || (len > buf.length)) {
25929564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath            return false;
26029564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        }
26129564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath
26229564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        buf[0] = (byte) (len & 0xff);
26329564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        buf[1] = (byte) ((len >> 8) & 0xff);
26429564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        try {
26529564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath            mOut.write(buf, 0, 2);
26629564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath            mOut.write(cmd, 0, len);
26729564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        } catch (IOException ex) {
26829564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath            Slog.e(TAG, "write error");
26929564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath            disconnect();
27029564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath            return false;
27129564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        }
27229564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        return true;
27329564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath    }
274c8a2cfed0192afc6a408f4bdb77e8a0bdd5d752bMakoto Onuki
275c8a2cfed0192afc6a408f4bdb77e8a0bdd5d752bMakoto Onuki    public void waitForConnection() {
276c8a2cfed0192afc6a408f4bdb77e8a0bdd5d752bMakoto Onuki        for (;;) {
277fdeeeea6cfdebdb98dd70a7dd48965743af01750Jeff Sharkey            try {
278fdeeeea6cfdebdb98dd70a7dd48965743af01750Jeff Sharkey                execute("ping");
279c8a2cfed0192afc6a408f4bdb77e8a0bdd5d752bMakoto Onuki                return;
280fdeeeea6cfdebdb98dd70a7dd48965743af01750Jeff Sharkey            } catch (InstallerException ignored) {
281c8a2cfed0192afc6a408f4bdb77e8a0bdd5d752bMakoto Onuki            }
282c8a2cfed0192afc6a408f4bdb77e8a0bdd5d752bMakoto Onuki            Slog.w(TAG, "installd not ready");
283c8a2cfed0192afc6a408f4bdb77e8a0bdd5d752bMakoto Onuki            SystemClock.sleep(1000);
284c8a2cfed0192afc6a408f4bdb77e8a0bdd5d752bMakoto Onuki        }
285c8a2cfed0192afc6a408f4bdb77e8a0bdd5d752bMakoto Onuki    }
286fdeeeea6cfdebdb98dd70a7dd48965743af01750Jeff Sharkey
287fdeeeea6cfdebdb98dd70a7dd48965743af01750Jeff Sharkey    public static class InstallerException extends Exception {
288fdeeeea6cfdebdb98dd70a7dd48965743af01750Jeff Sharkey        public InstallerException(String detailMessage) {
289fdeeeea6cfdebdb98dd70a7dd48965743af01750Jeff Sharkey            super(detailMessage);
290fdeeeea6cfdebdb98dd70a7dd48965743af01750Jeff Sharkey        }
291fdeeeea6cfdebdb98dd70a7dd48965743af01750Jeff Sharkey    }
29229564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath}
293