blob: 2f335be1a0859dc216827205d95ad31a180c8965 [file] [log] [blame]
Chung-yih Wang10e371f2009-06-10 18:45:14 +08001/*
2 * Copyright (C) 2009 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
17package android.security;
18
19import android.net.LocalSocketAddress;
20import android.net.LocalSocket;
21import android.util.Config;
22import android.util.Log;
23
24import java.io.IOException;
25import java.io.InputStream;
26import java.io.OutputStream;
27import java.net.Socket;
28
29/*
30 * ServiceCommand is used to connect to a service throught the local socket,
31 * and send out the command, return the result to the caller.
32 * {@hide}
33 */
34public class ServiceCommand {
35 public static final String SUCCESS = "0";
36 public static final String FAILED = "-1";
37
Chung-yih Wangeec11822009-07-02 00:22:04 +080038 // Opcodes for keystore commands.
39 public static final int LOCK = 0;
40 public static final int UNLOCK = 1;
41 public static final int PASSWD = 2;
42 public static final int GET_STATE = 3;
43 public static final int LIST_KEYS = 4;
44 public static final int GET_KEY = 5;
45 public static final int PUT_KEY = 6;
46 public static final int REMOVE_KEY = 7;
47 public static final int RESET = 8;
48 public static final int MAX_CMD_INDEX = 9;
49
50 public static final int BUFFER_LENGTH = 4096;
51
Chung-yih Wang10e371f2009-06-10 18:45:14 +080052 private String mServiceName;
53 private String mTag;
54 private InputStream mIn;
55 private OutputStream mOut;
56 private LocalSocket mSocket;
Chung-yih Wang10e371f2009-06-10 18:45:14 +080057
58 private boolean connect() {
59 if (mSocket != null) {
60 return true;
61 }
62 Log.i(mTag, "connecting...");
63 try {
64 mSocket = new LocalSocket();
65
66 LocalSocketAddress address = new LocalSocketAddress(
67 mServiceName, LocalSocketAddress.Namespace.RESERVED);
68
69 mSocket.connect(address);
70
71 mIn = mSocket.getInputStream();
72 mOut = mSocket.getOutputStream();
73 } catch (IOException ex) {
74 disconnect();
75 return false;
76 }
77 return true;
78 }
79
80 private void disconnect() {
81 Log.i(mTag,"disconnecting...");
82 try {
83 if (mSocket != null) mSocket.close();
84 } catch (IOException ex) { }
85 try {
86 if (mIn != null) mIn.close();
87 } catch (IOException ex) { }
88 try {
89 if (mOut != null) mOut.close();
90 } catch (IOException ex) { }
91 mSocket = null;
92 mIn = null;
93 mOut = null;
94 }
95
96 private boolean readBytes(byte buffer[], int len) {
97 int off = 0, count;
98 if (len < 0) return false;
99 while (off != len) {
100 try {
101 count = mIn.read(buffer, off, len - off);
102 if (count <= 0) {
103 Log.e(mTag, "read error " + count);
104 break;
105 }
106 off += count;
107 } catch (IOException ex) {
108 Log.e(mTag,"read exception");
109 break;
110 }
111 }
112 if (off == len) return true;
113 disconnect();
114 return false;
115 }
116
Chung-yih Wangeec11822009-07-02 00:22:04 +0800117 private Reply readReply() {
118 byte buf[] = new byte[4];
119 Reply reply = new Reply();
Chung-yih Wang10e371f2009-06-10 18:45:14 +0800120
Chung-yih Wangeec11822009-07-02 00:22:04 +0800121 if (!readBytes(buf, 4)) return null;
122 reply.len = (((int) buf[0]) & 0xff) | ((((int) buf[1]) & 0xff) << 8) |
123 ((((int) buf[2]) & 0xff) << 16) |
124 ((((int) buf[3]) & 0xff) << 24);
Chung-yih Wang10e371f2009-06-10 18:45:14 +0800125
Chung-yih Wangeec11822009-07-02 00:22:04 +0800126 if (!readBytes(buf, 4)) return null;
127 reply.returnCode = (((int) buf[0]) & 0xff) |
128 ((((int) buf[1]) & 0xff) << 8) |
129 ((((int) buf[2]) & 0xff) << 16) |
130 ((((int) buf[3]) & 0xff) << 24);
131
132 if (reply.len > BUFFER_LENGTH) {
133 Log.e(mTag,"invalid reply length (" + reply.len + ")");
Chung-yih Wang10e371f2009-06-10 18:45:14 +0800134 disconnect();
Chung-yih Wangeec11822009-07-02 00:22:04 +0800135 return null;
Chung-yih Wang10e371f2009-06-10 18:45:14 +0800136 }
Chung-yih Wangeec11822009-07-02 00:22:04 +0800137 if (!readBytes(reply.data, reply.len)) return null;
138 return reply;
Chung-yih Wang10e371f2009-06-10 18:45:14 +0800139 }
140
Chung-yih Wangeec11822009-07-02 00:22:04 +0800141 private boolean writeCommand(int cmd, String _data) {
142 byte buf[] = new byte[8];
143 byte[] data = _data.getBytes();
144 int len = data.length;
145 // the length of data
Chung-yih Wang10e371f2009-06-10 18:45:14 +0800146 buf[0] = (byte) (len & 0xff);
147 buf[1] = (byte) ((len >> 8) & 0xff);
Chung-yih Wangeec11822009-07-02 00:22:04 +0800148 buf[2] = (byte) ((len >> 16) & 0xff);
149 buf[3] = (byte) ((len >> 24) & 0xff);
150 // the opcode of the command
151 buf[4] = (byte) (cmd & 0xff);
152 buf[5] = (byte) ((cmd >> 8) & 0xff);
153 buf[6] = (byte) ((cmd >> 16) & 0xff);
154 buf[7] = (byte) ((cmd >> 24) & 0xff);
Chung-yih Wang10e371f2009-06-10 18:45:14 +0800155 try {
Chung-yih Wangeec11822009-07-02 00:22:04 +0800156 mOut.write(buf, 0, 8);
157 mOut.write(data, 0, len);
Chung-yih Wang10e371f2009-06-10 18:45:14 +0800158 } catch (IOException ex) {
159 Log.e(mTag,"write error");
160 disconnect();
161 return false;
162 }
163 return true;
164 }
165
Chung-yih Wangeec11822009-07-02 00:22:04 +0800166 private Reply executeCommand(int cmd, String data) {
167 if (!writeCommand(cmd, data)) {
Chung-yih Wang10e371f2009-06-10 18:45:14 +0800168 /* If service died and restarted in the background
169 * (unlikely but possible) we'll fail on the next
170 * write (this one). Try to reconnect and write
171 * the command one more time before giving up.
172 */
173 Log.e(mTag, "write command failed? reconnect!");
Chung-yih Wangeec11822009-07-02 00:22:04 +0800174 if (!connect() || !writeCommand(cmd, data)) {
Chung-yih Wang10e371f2009-06-10 18:45:14 +0800175 return null;
176 }
177 }
Chung-yih Wangeec11822009-07-02 00:22:04 +0800178 return readReply();
Chung-yih Wang10e371f2009-06-10 18:45:14 +0800179 }
180
Chung-yih Wangeec11822009-07-02 00:22:04 +0800181 public synchronized Reply execute(int cmd, String data) {
182 Reply result;
Chung-yih Wang10e371f2009-06-10 18:45:14 +0800183 if (!connect()) {
184 Log.e(mTag, "connection failed");
185 return null;
186 }
Chung-yih Wangeec11822009-07-02 00:22:04 +0800187 result = executeCommand(cmd, data);
Chung-yih Wang10e371f2009-06-10 18:45:14 +0800188 disconnect();
189 return result;
190 }
191
192 public ServiceCommand(String service) {
193 mServiceName = service;
194 mTag = service;
195 }
196}