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;
2129564cd24589867f653cd22cabbaac6493cfc530Narayan Kamathimport android.util.Slog;
2229564cd24589867f653cd22cabbaac6493cfc530Narayan Kamathimport libcore.io.IoUtils;
2329564cd24589867f653cd22cabbaac6493cfc530Narayan Kamathimport libcore.io.Streams;
2429564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath
2529564cd24589867f653cd22cabbaac6493cfc530Narayan Kamathimport java.io.IOException;
2629564cd24589867f653cd22cabbaac6493cfc530Narayan Kamathimport java.io.InputStream;
2729564cd24589867f653cd22cabbaac6493cfc530Narayan Kamathimport java.io.OutputStream;
2829564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath
2929564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath/**
3029564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath * Represents a connection to {@code installd}. Allows multiple connect and
3129564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath * disconnect cycles.
3229564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath *
3329564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath * @hide for internal use only
3429564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath */
3529564cd24589867f653cd22cabbaac6493cfc530Narayan Kamathpublic class InstallerConnection {
3629564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath    private static final String TAG = "InstallerConnection";
3729564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath    private static final boolean LOCAL_DEBUG = false;
3829564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath
3929564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath    private InputStream mIn;
4029564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath    private OutputStream mOut;
4129564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath    private LocalSocket mSocket;
4229564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath
4329564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath    private final byte buf[] = new byte[1024];
4429564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath
4529564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath    public InstallerConnection() {
4629564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath    }
4729564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath
4829564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath    public synchronized String transact(String cmd) {
4929564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        if (!connect()) {
5029564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath            Slog.e(TAG, "connection failed");
5129564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath            return "-1";
5229564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        }
5329564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath
5429564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        if (!writeCommand(cmd)) {
5529564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath            /*
5629564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath             * If installd died and restarted in the background (unlikely but
5729564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath             * possible) we'll fail on the next write (this one). Try to
5829564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath             * reconnect and write the command one more time before giving up.
5929564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath             */
6029564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath            Slog.e(TAG, "write command failed? reconnect!");
6129564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath            if (!connect() || !writeCommand(cmd)) {
6229564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath                return "-1";
6329564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath            }
6429564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        }
6529564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        if (LOCAL_DEBUG) {
6629564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath            Slog.i(TAG, "send: '" + cmd + "'");
6729564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        }
6829564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath
6929564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        final int replyLength = readReply();
7029564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        if (replyLength > 0) {
7129564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath            String s = new String(buf, 0, replyLength);
7229564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath            if (LOCAL_DEBUG) {
7329564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath                Slog.i(TAG, "recv: '" + s + "'");
7429564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath            }
7529564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath            return s;
7629564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        } else {
7729564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath            if (LOCAL_DEBUG) {
7829564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath                Slog.i(TAG, "fail");
7929564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath            }
8029564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath            return "-1";
8129564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        }
8229564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath    }
8329564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath
8429564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath    public int execute(String cmd) {
8529564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        String res = transact(cmd);
8629564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        try {
8729564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath            return Integer.parseInt(res);
8829564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        } catch (NumberFormatException ex) {
8929564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath            return -1;
9029564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        }
9129564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath    }
9229564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath
9329564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath    public int dexopt(String apkPath, int uid, boolean isPublic, String instructionSet) {
94feb193085adbdc379ee70dbb7dc6ae4c9f2971ddCalin Juravle        return dexopt(apkPath, uid, isPublic, "*", instructionSet, false);
95feb193085adbdc379ee70dbb7dc6ae4c9f2971ddCalin Juravle    }
96feb193085adbdc379ee70dbb7dc6ae4c9f2971ddCalin Juravle
97feb193085adbdc379ee70dbb7dc6ae4c9f2971ddCalin Juravle    public int dexopt(String apkPath, int uid, boolean isPublic, String pkgName,
98feb193085adbdc379ee70dbb7dc6ae4c9f2971ddCalin Juravle            String instructionSet, boolean vmSafeMode) {
9929564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        StringBuilder builder = new StringBuilder("dexopt");
10029564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        builder.append(' ');
10129564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        builder.append(apkPath);
10229564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        builder.append(' ');
10329564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        builder.append(uid);
10429564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        builder.append(isPublic ? " 1" : " 0");
105feb193085adbdc379ee70dbb7dc6ae4c9f2971ddCalin Juravle        builder.append(' ');
106feb193085adbdc379ee70dbb7dc6ae4c9f2971ddCalin Juravle        builder.append(pkgName);
10729564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        builder.append(' ');
10829564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        builder.append(instructionSet);
109feb193085adbdc379ee70dbb7dc6ae4c9f2971ddCalin Juravle        builder.append(' ');
110feb193085adbdc379ee70dbb7dc6ae4c9f2971ddCalin Juravle        builder.append(vmSafeMode ? " 1" : " 0");
11129564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        return execute(builder.toString());
11229564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath    }
11329564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath
11429564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath    public int patchoat(String apkPath, int uid, boolean isPublic, String instructionSet) {
115feb193085adbdc379ee70dbb7dc6ae4c9f2971ddCalin Juravle        return patchoat(apkPath, uid, isPublic, "*", instructionSet);
116feb193085adbdc379ee70dbb7dc6ae4c9f2971ddCalin Juravle    }
117feb193085adbdc379ee70dbb7dc6ae4c9f2971ddCalin Juravle
118feb193085adbdc379ee70dbb7dc6ae4c9f2971ddCalin Juravle    public int patchoat(String apkPath, int uid, boolean isPublic, String pkgName,
119feb193085adbdc379ee70dbb7dc6ae4c9f2971ddCalin Juravle            String instructionSet) {
12029564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        StringBuilder builder = new StringBuilder("patchoat");
12129564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        builder.append(' ');
12229564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        builder.append(apkPath);
12329564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        builder.append(' ');
12429564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        builder.append(uid);
12529564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        builder.append(isPublic ? " 1" : " 0");
126feb193085adbdc379ee70dbb7dc6ae4c9f2971ddCalin Juravle        builder.append(' ');
127feb193085adbdc379ee70dbb7dc6ae4c9f2971ddCalin Juravle        builder.append(pkgName);
12829564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        builder.append(' ');
12929564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        builder.append(instructionSet);
13029564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        return execute(builder.toString());
13129564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath    }
13229564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath
13329564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath    private boolean connect() {
13429564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        if (mSocket != null) {
13529564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath            return true;
13629564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        }
13729564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        Slog.i(TAG, "connecting...");
13829564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        try {
13929564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath            mSocket = new LocalSocket();
14029564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath
14129564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath            LocalSocketAddress address = new LocalSocketAddress("installd",
14229564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath                    LocalSocketAddress.Namespace.RESERVED);
14329564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath
14429564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath            mSocket.connect(address);
14529564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath
14629564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath            mIn = mSocket.getInputStream();
14729564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath            mOut = mSocket.getOutputStream();
14829564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        } catch (IOException ex) {
14929564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath            disconnect();
15029564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath            return false;
15129564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        }
15229564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        return true;
15329564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath    }
15429564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath
15529564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath    public void disconnect() {
15629564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        Slog.i(TAG, "disconnecting...");
15729564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        IoUtils.closeQuietly(mSocket);
15829564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        IoUtils.closeQuietly(mIn);
15929564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        IoUtils.closeQuietly(mOut);
16029564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath
16129564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        mSocket = null;
16229564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        mIn = null;
16329564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        mOut = null;
16429564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath    }
16529564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath
16629564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath
16729564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath    private boolean readFully(byte[] buffer, int len) {
16829564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        try {
16929564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath            Streams.readFully(mIn, buffer, 0, len);
17029564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        } catch (IOException ioe) {
17129564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath            Slog.e(TAG, "read exception");
17229564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath            disconnect();
17329564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath            return false;
17429564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        }
17529564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath
17629564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        if (LOCAL_DEBUG) {
17729564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath            Slog.i(TAG, "read " + len + " bytes");
17829564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        }
17929564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath
18029564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        return true;
18129564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath    }
18229564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath
18329564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath    private int readReply() {
18429564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        if (!readFully(buf, 2)) {
18529564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath            return -1;
18629564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        }
18729564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath
18829564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        final int len = (((int) buf[0]) & 0xff) | ((((int) buf[1]) & 0xff) << 8);
18929564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        if ((len < 1) || (len > buf.length)) {
19029564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath            Slog.e(TAG, "invalid reply length (" + len + ")");
19129564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath            disconnect();
19229564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath            return -1;
19329564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        }
19429564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath
19529564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        if (!readFully(buf, len)) {
19629564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath            return -1;
19729564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        }
19829564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath
19929564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        return len;
20029564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath    }
20129564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath
20229564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath    private boolean writeCommand(String cmdString) {
20329564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        final byte[] cmd = cmdString.getBytes();
20429564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        final int len = cmd.length;
20529564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        if ((len < 1) || (len > buf.length)) {
20629564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath            return false;
20729564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        }
20829564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath
20929564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        buf[0] = (byte) (len & 0xff);
21029564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        buf[1] = (byte) ((len >> 8) & 0xff);
21129564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        try {
21229564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath            mOut.write(buf, 0, 2);
21329564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath            mOut.write(cmd, 0, len);
21429564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        } catch (IOException ex) {
21529564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath            Slog.e(TAG, "write error");
21629564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath            disconnect();
21729564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath            return false;
21829564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        }
21929564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath        return true;
22029564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath    }
22129564cd24589867f653cd22cabbaac6493cfc530Narayan Kamath}
222