blob: df54c7fe289b45de528e776aadb0719b632fc4e2 [file] [log] [blame]
Ye Wend97e1fd2014-07-24 12:56:45 -07001/*
2 * Copyright (C) 2014 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 com.android.server;
18
19import com.android.internal.telephony.IMms;
20
21import android.Manifest;
22import android.app.AppOpsManager;
23import android.app.PendingIntent;
24import android.content.ComponentName;
25import android.content.ContentValues;
26import android.content.Context;
27import android.content.Intent;
28import android.content.ServiceConnection;
29import android.content.pm.PackageManager;
30import android.net.Uri;
31import android.os.Binder;
32import android.os.Handler;
33import android.os.IBinder;
34import android.os.Message;
35import android.os.RemoteException;
36import android.telephony.TelephonyManager;
37import android.util.Slog;
38
39/**
40 * This class is a proxy for MmsService APIs. We need this because MmsService runs
41 * in phone process and may crash anytime. This manages a connection to the actual
42 * MmsService and bridges the public SMS/MMS APIs with MmsService implementation.
43 */
44public class MmsServiceBroker extends SystemService {
45 private static final String TAG = "MmsServiceBroker";
46
47 private static final ComponentName MMS_SERVICE_COMPONENT =
48 new ComponentName("com.android.mms.service", "com.android.mms.service.MmsService");
49
50 private static final int MSG_TRY_CONNECTING = 1;
51
Ye Wenfa58ac02014-07-31 17:15:30 -070052 private static final Uri FAKE_SMS_SENT_URI = Uri.parse("content://sms/sent/0");
53 private static final Uri FAKE_MMS_SENT_URI = Uri.parse("content://mms/sent/0");
54 private static final Uri FAKE_SMS_DRAFT_URI = Uri.parse("content://sms/draft/0");
55 private static final Uri FAKE_MMS_DRAFT_URI = Uri.parse("content://mms/draft/0");
56
Ye Wend97e1fd2014-07-24 12:56:45 -070057 private Context mContext;
58 // The actual MMS service instance to invoke
59 private volatile IMms mService;
60 private boolean mIsConnecting;
61
62 // Cached system service instances
63 private volatile AppOpsManager mAppOpsManager = null;
64 private volatile PackageManager mPackageManager = null;
65 private volatile TelephonyManager mTelephonyManager = null;
66
67 private final Handler mConnectionHandler = new Handler() {
68 @Override
69 public void handleMessage(Message msg) {
70 switch (msg.what) {
71 case MSG_TRY_CONNECTING:
72 tryConnecting();
73 break;
74 default:
75 Slog.e(TAG, "Unknown message");
76 }
77 }
78 };
79
80 private ServiceConnection mConnection = new ServiceConnection() {
81 @Override
82 public void onServiceConnected(ComponentName name, IBinder service) {
83 Slog.i(TAG, "MmsService connected");
84 synchronized (MmsServiceBroker.this) {
85 mService = IMms.Stub.asInterface(service);
86 mIsConnecting = false;
87 }
88 }
89
90 @Override
91 public void onServiceDisconnected(ComponentName name) {
92 Slog.i(TAG, "MmsService unexpectedly disconnected");
93 synchronized (MmsServiceBroker.this) {
94 mService = null;
95 mIsConnecting = false;
96 }
97 }
98 };
99
100 public MmsServiceBroker(Context context) {
101 super(context);
102 mContext = context;
103 mService = null;
104 mIsConnecting = false;
105 }
106
107 @Override
108 public void onStart() {
109 publishBinderService("imms", new BinderService());
110 }
111
112 public void systemRunning() {
113 tryConnecting();
114 }
115
116 private void tryConnecting() {
117 Slog.i(TAG, "Connecting to MmsService");
118 synchronized (this) {
119 if (mIsConnecting) {
120 Slog.d(TAG, "Already connecting");
121 return;
122 }
123 final Intent intent = new Intent();
124 intent.setComponent(MMS_SERVICE_COMPONENT);
125 try {
126 if (mContext.bindService(intent, mConnection, Context.BIND_AUTO_CREATE)) {
127 mIsConnecting = true;
128 } else {
129 Slog.e(TAG, "Failed to connect to MmsService");
130 }
131 } catch (SecurityException e) {
132 Slog.e(TAG, "Forbidden to connect to MmsService", e);
133 }
134 }
135 }
136
137 private void ensureService() {
138 if (mService == null) {
139 // Service instance lost, kicking off the connection again
140 mConnectionHandler.sendMessage(mConnectionHandler.obtainMessage(MSG_TRY_CONNECTING));
141 throw new RuntimeException("MMS service is not connected");
142 }
143 }
144
145 /**
146 * Making sure when we obtain the mService instance it is always valid.
147 * Throws {@link RuntimeException} when it is empty.
148 */
149 private IMms getServiceGuarded() {
150 ensureService();
151 return mService;
152 }
153
154 private AppOpsManager getAppOpsManager() {
155 if (mAppOpsManager == null) {
156 mAppOpsManager = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
157 }
158 return mAppOpsManager;
159 }
160
161 private PackageManager getPackageManager() {
162 if (mPackageManager == null) {
163 mPackageManager = mContext.getPackageManager();
164 }
165 return mPackageManager;
166 }
167
168 private TelephonyManager getTelephonyManager() {
169 if (mTelephonyManager == null) {
170 mTelephonyManager = (TelephonyManager) mContext.getSystemService(
171 Context.TELEPHONY_SERVICE);
172 }
173 return mTelephonyManager;
174 }
175
176 /*
177 * Throws a security exception unless the caller has carrier privilege.
178 */
179 private void enforceCarrierPrivilege() {
180 String[] packages = getPackageManager().getPackagesForUid(Binder.getCallingUid());
181 for (String pkg : packages) {
182 if (getTelephonyManager().checkCarrierPrivilegesForPackage(pkg) ==
183 TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
184 return;
185 }
186 }
187 throw new SecurityException("No carrier privilege");
188 }
189
190 // Service API calls implementation, proxied to the real MmsService in "com.android.mms.service"
191 private final class BinderService extends IMms.Stub {
192 @Override
193 public void sendMessage(long subId, String callingPkg, byte[] pdu, String locationUrl,
Ye Wen63c00c42014-08-01 13:38:58 -0700194 ContentValues configOverrides, PendingIntent sentIntent) throws RemoteException {
Ye Wend97e1fd2014-07-24 12:56:45 -0700195 mContext.enforceCallingPermission(Manifest.permission.SEND_SMS, "Send MMS message");
196 if (getAppOpsManager().noteOp(AppOpsManager.OP_SEND_SMS, Binder.getCallingUid(),
197 callingPkg) != AppOpsManager.MODE_ALLOWED) {
198 return;
199 }
Ye Wen63c00c42014-08-01 13:38:58 -0700200 getServiceGuarded().sendMessage(subId, callingPkg, pdu, locationUrl, configOverrides,
201 sentIntent);
Ye Wend97e1fd2014-07-24 12:56:45 -0700202 }
203
204 @Override
205 public void downloadMessage(long subId, String callingPkg, String locationUrl,
Ye Wen63c00c42014-08-01 13:38:58 -0700206 ContentValues configOverrides, PendingIntent downloadedIntent)
207 throws RemoteException {
Ye Wend97e1fd2014-07-24 12:56:45 -0700208 mContext.enforceCallingPermission(Manifest.permission.RECEIVE_MMS,
209 "Download MMS message");
210 if (getAppOpsManager().noteOp(AppOpsManager.OP_RECEIVE_MMS, Binder.getCallingUid(),
211 callingPkg) != AppOpsManager.MODE_ALLOWED) {
212 return;
213 }
Ye Wen63c00c42014-08-01 13:38:58 -0700214 getServiceGuarded().downloadMessage(subId, callingPkg, locationUrl, configOverrides,
215 downloadedIntent);
Ye Wend97e1fd2014-07-24 12:56:45 -0700216 }
217
218 @Override
219 public void updateMmsSendStatus(int messageRef, boolean success) throws RemoteException {
220 enforceCarrierPrivilege();
221 getServiceGuarded().updateMmsSendStatus(messageRef, success);
222 }
223
224 @Override
225 public void updateMmsDownloadStatus(int messageRef, byte[] pdu) throws RemoteException {
226 enforceCarrierPrivilege();
227 getServiceGuarded().updateMmsDownloadStatus(messageRef, pdu);
228 }
229
230 @Override
Ye Wen63c00c42014-08-01 13:38:58 -0700231 public boolean getCarrierConfigBoolean(long subId, String name, boolean defaultValue)
Ye Wend97e1fd2014-07-24 12:56:45 -0700232 throws RemoteException {
Ye Wen63c00c42014-08-01 13:38:58 -0700233 return getServiceGuarded().getCarrierConfigBoolean(subId, name, defaultValue);
Ye Wend97e1fd2014-07-24 12:56:45 -0700234 }
235
236 @Override
Ye Wen63c00c42014-08-01 13:38:58 -0700237 public int getCarrierConfigInt(long subId, String name, int defaultValue)
238 throws RemoteException {
239 return getServiceGuarded().getCarrierConfigInt(subId, name, defaultValue);
Ye Wend97e1fd2014-07-24 12:56:45 -0700240 }
241
242 @Override
Ye Wen63c00c42014-08-01 13:38:58 -0700243 public String getCarrierConfigString(long subId, String name, String defaultValue)
Ye Wend97e1fd2014-07-24 12:56:45 -0700244 throws RemoteException {
Ye Wen63c00c42014-08-01 13:38:58 -0700245 return getServiceGuarded().getCarrierConfigString(subId, name, defaultValue);
Ye Wend97e1fd2014-07-24 12:56:45 -0700246 }
247
248 @Override
249 public Uri importTextMessage(String callingPkg, String address, int type, String text,
250 long timestampMillis, boolean seen, boolean read) throws RemoteException {
251 mContext.enforceCallingPermission(Manifest.permission.WRITE_SMS, "Import SMS message");
252 if (getAppOpsManager().noteOp(AppOpsManager.OP_WRITE_SMS, Binder.getCallingUid(),
253 callingPkg) != AppOpsManager.MODE_ALLOWED) {
Ye Wenfa58ac02014-07-31 17:15:30 -0700254 // Silently fail AppOps failure due to not being the default SMS app
255 // while writing the TelephonyProvider
256 return FAKE_SMS_SENT_URI;
Ye Wend97e1fd2014-07-24 12:56:45 -0700257 }
258 return getServiceGuarded().importTextMessage(
259 callingPkg, address, type, text, timestampMillis, seen, read);
260 }
261
262 @Override
263 public Uri importMultimediaMessage(String callingPkg, byte[] pdu, String messageId,
264 long timestampSecs, boolean seen, boolean read) throws RemoteException {
265 mContext.enforceCallingPermission(Manifest.permission.WRITE_SMS, "Import MMS message");
266 if (getAppOpsManager().noteOp(AppOpsManager.OP_WRITE_SMS, Binder.getCallingUid(),
267 callingPkg) != AppOpsManager.MODE_ALLOWED) {
Ye Wenfa58ac02014-07-31 17:15:30 -0700268 // Silently fail AppOps failure due to not being the default SMS app
269 // while writing the TelephonyProvider
270 return FAKE_MMS_SENT_URI;
Ye Wend97e1fd2014-07-24 12:56:45 -0700271 }
272 return getServiceGuarded().importMultimediaMessage(
273 callingPkg, pdu, messageId, timestampSecs, seen, read);
274 }
275
276 @Override
277 public boolean deleteStoredMessage(String callingPkg, Uri messageUri)
278 throws RemoteException {
279 mContext.enforceCallingPermission(Manifest.permission.WRITE_SMS,
280 "Delete SMS/MMS message");
281 if (getAppOpsManager().noteOp(AppOpsManager.OP_WRITE_SMS, Binder.getCallingUid(),
282 callingPkg) != AppOpsManager.MODE_ALLOWED) {
283 return false;
284 }
285 return getServiceGuarded().deleteStoredMessage(callingPkg, messageUri);
286 }
287
288 @Override
289 public boolean deleteStoredConversation(String callingPkg, long conversationId)
290 throws RemoteException {
291 mContext.enforceCallingPermission(Manifest.permission.WRITE_SMS, "Delete conversation");
292 if (getAppOpsManager().noteOp(AppOpsManager.OP_WRITE_SMS, Binder.getCallingUid(),
293 callingPkg) != AppOpsManager.MODE_ALLOWED) {
294 return false;
295 }
296 return getServiceGuarded().deleteStoredConversation(callingPkg, conversationId);
297 }
298
299 @Override
300 public boolean updateStoredMessageStatus(String callingPkg, Uri messageUri,
301 ContentValues statusValues) throws RemoteException {
302 mContext.enforceCallingPermission(Manifest.permission.WRITE_SMS,
303 "Update SMS/MMS message");
304 return getServiceGuarded()
305 .updateStoredMessageStatus(callingPkg, messageUri, statusValues);
306 }
307
308 @Override
Ye Wena3dbd102014-07-29 10:42:25 -0700309 public boolean archiveStoredConversation(String callingPkg, long conversationId,
310 boolean archived) throws RemoteException {
311 mContext.enforceCallingPermission(Manifest.permission.WRITE_SMS,
312 "Update SMS/MMS message");
313 return getServiceGuarded()
314 .archiveStoredConversation(callingPkg, conversationId, archived);
315 }
316
317 @Override
Ye Wend97e1fd2014-07-24 12:56:45 -0700318 public Uri addTextMessageDraft(String callingPkg, String address, String text)
319 throws RemoteException {
320 mContext.enforceCallingPermission(Manifest.permission.WRITE_SMS, "Add SMS draft");
321 if (getAppOpsManager().noteOp(AppOpsManager.OP_WRITE_SMS, Binder.getCallingUid(),
322 callingPkg) != AppOpsManager.MODE_ALLOWED) {
Ye Wenfa58ac02014-07-31 17:15:30 -0700323 // Silently fail AppOps failure due to not being the default SMS app
324 // while writing the TelephonyProvider
325 return FAKE_SMS_DRAFT_URI;
Ye Wend97e1fd2014-07-24 12:56:45 -0700326 }
327 return getServiceGuarded().addTextMessageDraft(callingPkg, address, text);
328 }
329
330 @Override
331 public Uri addMultimediaMessageDraft(String callingPkg, byte[] pdu) throws RemoteException {
332 mContext.enforceCallingPermission(Manifest.permission.WRITE_SMS, "Add MMS draft");
333 if (getAppOpsManager().noteOp(AppOpsManager.OP_WRITE_SMS, Binder.getCallingUid(),
334 callingPkg) != AppOpsManager.MODE_ALLOWED) {
Ye Wenfa58ac02014-07-31 17:15:30 -0700335 // Silently fail AppOps failure due to not being the default SMS app
336 // while writing the TelephonyProvider
337 return FAKE_MMS_DRAFT_URI;
Ye Wend97e1fd2014-07-24 12:56:45 -0700338 }
339 return getServiceGuarded().addMultimediaMessageDraft(callingPkg, pdu);
340 }
341
342 @Override
343 public void sendStoredMessage(long subId, String callingPkg, Uri messageUri,
Ye Wen63c00c42014-08-01 13:38:58 -0700344 ContentValues configOverrides, PendingIntent sentIntent) throws RemoteException {
Ye Wend97e1fd2014-07-24 12:56:45 -0700345 mContext.enforceCallingPermission(Manifest.permission.SEND_SMS,
346 "Send stored MMS message");
347 if (getAppOpsManager().noteOp(AppOpsManager.OP_SEND_SMS, Binder.getCallingUid(),
348 callingPkg) != AppOpsManager.MODE_ALLOWED) {
349 return;
350 }
Ye Wen63c00c42014-08-01 13:38:58 -0700351 getServiceGuarded().sendStoredMessage(subId, callingPkg, messageUri, configOverrides,
352 sentIntent);
Ye Wend97e1fd2014-07-24 12:56:45 -0700353 }
354
355 @Override
356 public void setAutoPersisting(String callingPkg, boolean enabled) throws RemoteException {
357 mContext.enforceCallingPermission(Manifest.permission.WRITE_SMS, "Set auto persist");
358 if (getAppOpsManager().noteOp(AppOpsManager.OP_WRITE_SMS, Binder.getCallingUid(),
359 callingPkg) != AppOpsManager.MODE_ALLOWED) {
360 return;
361 }
362 getServiceGuarded().setAutoPersisting(callingPkg, enabled);
363 }
364
365 @Override
366 public boolean getAutoPersisting() throws RemoteException {
367 return getServiceGuarded().getAutoPersisting();
368 }
369 }
370}