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