Home | History | Annotate | Download | only in os
      1 /*
      2  * Copyright (C) 2008 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
      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 
     17 package com.android.internal.os;
     18 
     19 import android.net.LocalSocket;
     20 import android.net.LocalSocketAddress;
     21 import android.util.Slog;
     22 import libcore.io.IoUtils;
     23 import libcore.io.Streams;
     24 
     25 import java.io.IOException;
     26 import java.io.InputStream;
     27 import java.io.OutputStream;
     28 
     29 /**
     30  * Represents a connection to {@code installd}. Allows multiple connect and
     31  * disconnect cycles.
     32  *
     33  * @hide for internal use only
     34  */
     35 public class InstallerConnection {
     36     private static final String TAG = "InstallerConnection";
     37     private static final boolean LOCAL_DEBUG = false;
     38 
     39     private InputStream mIn;
     40     private OutputStream mOut;
     41     private LocalSocket mSocket;
     42 
     43     private final byte buf[] = new byte[1024];
     44 
     45     public InstallerConnection() {
     46     }
     47 
     48     public synchronized String transact(String cmd) {
     49         if (!connect()) {
     50             Slog.e(TAG, "connection failed");
     51             return "-1";
     52         }
     53 
     54         if (!writeCommand(cmd)) {
     55             /*
     56              * If installd died and restarted in the background (unlikely but
     57              * possible) we'll fail on the next write (this one). Try to
     58              * reconnect and write the command one more time before giving up.
     59              */
     60             Slog.e(TAG, "write command failed? reconnect!");
     61             if (!connect() || !writeCommand(cmd)) {
     62                 return "-1";
     63             }
     64         }
     65         if (LOCAL_DEBUG) {
     66             Slog.i(TAG, "send: '" + cmd + "'");
     67         }
     68 
     69         final int replyLength = readReply();
     70         if (replyLength > 0) {
     71             String s = new String(buf, 0, replyLength);
     72             if (LOCAL_DEBUG) {
     73                 Slog.i(TAG, "recv: '" + s + "'");
     74             }
     75             return s;
     76         } else {
     77             if (LOCAL_DEBUG) {
     78                 Slog.i(TAG, "fail");
     79             }
     80             return "-1";
     81         }
     82     }
     83 
     84     public int execute(String cmd) {
     85         String res = transact(cmd);
     86         try {
     87             return Integer.parseInt(res);
     88         } catch (NumberFormatException ex) {
     89             return -1;
     90         }
     91     }
     92 
     93     public int dexopt(String apkPath, int uid, boolean isPublic, String instructionSet) {
     94         return dexopt(apkPath, uid, isPublic, "*", instructionSet, false);
     95     }
     96 
     97     public int dexopt(String apkPath, int uid, boolean isPublic, String pkgName,
     98             String instructionSet, boolean vmSafeMode) {
     99         StringBuilder builder = new StringBuilder("dexopt");
    100         builder.append(' ');
    101         builder.append(apkPath);
    102         builder.append(' ');
    103         builder.append(uid);
    104         builder.append(isPublic ? " 1" : " 0");
    105         builder.append(' ');
    106         builder.append(pkgName);
    107         builder.append(' ');
    108         builder.append(instructionSet);
    109         builder.append(' ');
    110         builder.append(vmSafeMode ? " 1" : " 0");
    111         return execute(builder.toString());
    112     }
    113 
    114     public int patchoat(String apkPath, int uid, boolean isPublic, String instructionSet) {
    115         return patchoat(apkPath, uid, isPublic, "*", instructionSet);
    116     }
    117 
    118     public int patchoat(String apkPath, int uid, boolean isPublic, String pkgName,
    119             String instructionSet) {
    120         StringBuilder builder = new StringBuilder("patchoat");
    121         builder.append(' ');
    122         builder.append(apkPath);
    123         builder.append(' ');
    124         builder.append(uid);
    125         builder.append(isPublic ? " 1" : " 0");
    126         builder.append(' ');
    127         builder.append(pkgName);
    128         builder.append(' ');
    129         builder.append(instructionSet);
    130         return execute(builder.toString());
    131     }
    132 
    133     private boolean connect() {
    134         if (mSocket != null) {
    135             return true;
    136         }
    137         Slog.i(TAG, "connecting...");
    138         try {
    139             mSocket = new LocalSocket();
    140 
    141             LocalSocketAddress address = new LocalSocketAddress("installd",
    142                     LocalSocketAddress.Namespace.RESERVED);
    143 
    144             mSocket.connect(address);
    145 
    146             mIn = mSocket.getInputStream();
    147             mOut = mSocket.getOutputStream();
    148         } catch (IOException ex) {
    149             disconnect();
    150             return false;
    151         }
    152         return true;
    153     }
    154 
    155     public void disconnect() {
    156         Slog.i(TAG, "disconnecting...");
    157         IoUtils.closeQuietly(mSocket);
    158         IoUtils.closeQuietly(mIn);
    159         IoUtils.closeQuietly(mOut);
    160 
    161         mSocket = null;
    162         mIn = null;
    163         mOut = null;
    164     }
    165 
    166 
    167     private boolean readFully(byte[] buffer, int len) {
    168         try {
    169             Streams.readFully(mIn, buffer, 0, len);
    170         } catch (IOException ioe) {
    171             Slog.e(TAG, "read exception");
    172             disconnect();
    173             return false;
    174         }
    175 
    176         if (LOCAL_DEBUG) {
    177             Slog.i(TAG, "read " + len + " bytes");
    178         }
    179 
    180         return true;
    181     }
    182 
    183     private int readReply() {
    184         if (!readFully(buf, 2)) {
    185             return -1;
    186         }
    187 
    188         final int len = (((int) buf[0]) & 0xff) | ((((int) buf[1]) & 0xff) << 8);
    189         if ((len < 1) || (len > buf.length)) {
    190             Slog.e(TAG, "invalid reply length (" + len + ")");
    191             disconnect();
    192             return -1;
    193         }
    194 
    195         if (!readFully(buf, len)) {
    196             return -1;
    197         }
    198 
    199         return len;
    200     }
    201 
    202     private boolean writeCommand(String cmdString) {
    203         final byte[] cmd = cmdString.getBytes();
    204         final int len = cmd.length;
    205         if ((len < 1) || (len > buf.length)) {
    206             return false;
    207         }
    208 
    209         buf[0] = (byte) (len & 0xff);
    210         buf[1] = (byte) ((len >> 8) & 0xff);
    211         try {
    212             mOut.write(buf, 0, 2);
    213             mOut.write(cmd, 0, len);
    214         } catch (IOException ex) {
    215             Slog.e(TAG, "write error");
    216             disconnect();
    217             return false;
    218         }
    219         return true;
    220     }
    221 }
    222