blob: b1c495539715105c3a44e7a5181b7e28606ebb41 [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
Ye Wend97e1fd2014-07-24 12:56:45 -070019import android.Manifest;
20import android.app.AppOpsManager;
21import android.app.PendingIntent;
22import android.content.ComponentName;
Tom Taylor86201db2014-11-24 09:36:43 -080023import android.content.ContentProvider;
Ye Wend97e1fd2014-07-24 12:56:45 -070024import android.content.ContentValues;
25import android.content.Context;
26import android.content.Intent;
27import android.content.ServiceConnection;
28import android.content.pm.PackageManager;
29import android.net.Uri;
30import android.os.Binder;
Shri Borde72379722014-09-02 09:48:49 -070031import android.os.Bundle;
Ye Wend97e1fd2014-07-24 12:56:45 -070032import android.os.Handler;
33import android.os.IBinder;
34import android.os.Message;
35import android.os.RemoteException;
Ye Wen724dbbd72014-10-07 15:33:51 -070036import android.os.SystemClock;
Tom Taylor86201db2014-11-24 09:36:43 -080037import android.os.UserHandle;
38import android.provider.Telephony;
Ye Wend97e1fd2014-07-24 12:56:45 -070039import android.telephony.TelephonyManager;
40import android.util.Slog;
41
Ye Wenbdc3a462014-11-11 11:17:28 -080042import com.android.internal.telephony.IMms;
43
Tom Taylor86201db2014-11-24 09:36:43 -080044import java.util.List;
45
Ye Wend97e1fd2014-07-24 12:56:45 -070046/**
47 * This class is a proxy for MmsService APIs. We need this because MmsService runs
48 * in phone process and may crash anytime. This manages a connection to the actual
49 * MmsService and bridges the public SMS/MMS APIs with MmsService implementation.
50 */
51public class MmsServiceBroker extends SystemService {
52 private static final String TAG = "MmsServiceBroker";
53
54 private static final ComponentName MMS_SERVICE_COMPONENT =
55 new ComponentName("com.android.mms.service", "com.android.mms.service.MmsService");
56
57 private static final int MSG_TRY_CONNECTING = 1;
58
Ye Wenfa58ac02014-07-31 17:15:30 -070059 private static final Uri FAKE_SMS_SENT_URI = Uri.parse("content://sms/sent/0");
60 private static final Uri FAKE_MMS_SENT_URI = Uri.parse("content://mms/sent/0");
61 private static final Uri FAKE_SMS_DRAFT_URI = Uri.parse("content://sms/draft/0");
62 private static final Uri FAKE_MMS_DRAFT_URI = Uri.parse("content://mms/draft/0");
63
Ye Wen724dbbd72014-10-07 15:33:51 -070064 private static final long SERVICE_CONNECTION_WAIT_TIME_MS = 4 * 1000L; // 4 seconds
65 private static final long RETRY_DELAY_ON_DISCONNECTION_MS = 3 * 1000L; // 3 seconds
66
Ye Wend97e1fd2014-07-24 12:56:45 -070067 private Context mContext;
68 // The actual MMS service instance to invoke
69 private volatile IMms mService;
Ye Wend97e1fd2014-07-24 12:56:45 -070070
71 // Cached system service instances
72 private volatile AppOpsManager mAppOpsManager = null;
73 private volatile PackageManager mPackageManager = null;
74 private volatile TelephonyManager mTelephonyManager = null;
75
76 private final Handler mConnectionHandler = new Handler() {
77 @Override
78 public void handleMessage(Message msg) {
79 switch (msg.what) {
80 case MSG_TRY_CONNECTING:
81 tryConnecting();
82 break;
83 default:
84 Slog.e(TAG, "Unknown message");
85 }
86 }
87 };
88
89 private ServiceConnection mConnection = new ServiceConnection() {
90 @Override
91 public void onServiceConnected(ComponentName name, IBinder service) {
92 Slog.i(TAG, "MmsService connected");
93 synchronized (MmsServiceBroker.this) {
94 mService = IMms.Stub.asInterface(service);
Ye Wen724dbbd72014-10-07 15:33:51 -070095 MmsServiceBroker.this.notifyAll();
Ye Wend97e1fd2014-07-24 12:56:45 -070096 }
97 }
98
99 @Override
100 public void onServiceDisconnected(ComponentName name) {
101 Slog.i(TAG, "MmsService unexpectedly disconnected");
102 synchronized (MmsServiceBroker.this) {
103 mService = null;
Ye Wen724dbbd72014-10-07 15:33:51 -0700104 MmsServiceBroker.this.notifyAll();
Ye Wend97e1fd2014-07-24 12:56:45 -0700105 }
Ye Wen724dbbd72014-10-07 15:33:51 -0700106 // Retry connecting, but not too eager (with a delay)
107 // since it may come back by itself.
108 mConnectionHandler.sendMessageDelayed(
109 mConnectionHandler.obtainMessage(MSG_TRY_CONNECTING),
110 RETRY_DELAY_ON_DISCONNECTION_MS);
Ye Wend97e1fd2014-07-24 12:56:45 -0700111 }
112 };
113
114 public MmsServiceBroker(Context context) {
115 super(context);
116 mContext = context;
117 mService = null;
Ye Wend97e1fd2014-07-24 12:56:45 -0700118 }
119
120 @Override
121 public void onStart() {
122 publishBinderService("imms", new BinderService());
123 }
124
125 public void systemRunning() {
Ye Wenbdc3a462014-11-11 11:17:28 -0800126 Slog.i(TAG, "Delay connecting to MmsService until an API is called");
Ye Wend97e1fd2014-07-24 12:56:45 -0700127 }
128
129 private void tryConnecting() {
130 Slog.i(TAG, "Connecting to MmsService");
131 synchronized (this) {
Ye Wen724dbbd72014-10-07 15:33:51 -0700132 if (mService != null) {
133 Slog.d(TAG, "Already connected");
Ye Wend97e1fd2014-07-24 12:56:45 -0700134 return;
135 }
136 final Intent intent = new Intent();
137 intent.setComponent(MMS_SERVICE_COMPONENT);
138 try {
Ye Wen724dbbd72014-10-07 15:33:51 -0700139 if (!mContext.bindService(intent, mConnection, Context.BIND_AUTO_CREATE)) {
140 Slog.e(TAG, "Failed to bind to MmsService");
Ye Wend97e1fd2014-07-24 12:56:45 -0700141 }
142 } catch (SecurityException e) {
Ye Wen724dbbd72014-10-07 15:33:51 -0700143 Slog.e(TAG, "Forbidden to bind to MmsService", e);
Ye Wend97e1fd2014-07-24 12:56:45 -0700144 }
145 }
146 }
147
148 private void ensureService() {
Ye Wen724dbbd72014-10-07 15:33:51 -0700149 synchronized (this) {
150 if (mService == null) {
151 // Service is not connected. Try blocking connecting.
152 Slog.w(TAG, "MmsService not connected. Try connecting...");
153 mConnectionHandler.sendMessage(
154 mConnectionHandler.obtainMessage(MSG_TRY_CONNECTING));
155 final long shouldEnd =
156 SystemClock.elapsedRealtime() + SERVICE_CONNECTION_WAIT_TIME_MS;
157 long waitTime = SERVICE_CONNECTION_WAIT_TIME_MS;
158 while (waitTime > 0) {
159 try {
160 // TODO: consider using Java concurrent construct instead of raw object wait
161 this.wait(waitTime);
162 } catch (InterruptedException e) {
163 Slog.w(TAG, "Connection wait interrupted", e);
164 }
165 if (mService != null) {
166 // Success
167 return;
168 }
169 // Calculate remaining waiting time to make sure we wait the full timeout period
170 waitTime = shouldEnd - SystemClock.elapsedRealtime();
171 }
172 // Timed out. Something's really wrong.
173 Slog.e(TAG, "Can not connect to MmsService (timed out)");
174 throw new RuntimeException("Timed out in connecting to MmsService");
175 }
Ye Wend97e1fd2014-07-24 12:56:45 -0700176 }
177 }
178
179 /**
180 * Making sure when we obtain the mService instance it is always valid.
181 * Throws {@link RuntimeException} when it is empty.
182 */
183 private IMms getServiceGuarded() {
184 ensureService();
185 return mService;
186 }
187
188 private AppOpsManager getAppOpsManager() {
189 if (mAppOpsManager == null) {
190 mAppOpsManager = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
191 }
192 return mAppOpsManager;
193 }
194
195 private PackageManager getPackageManager() {
196 if (mPackageManager == null) {
197 mPackageManager = mContext.getPackageManager();
198 }
199 return mPackageManager;
200 }
201
202 private TelephonyManager getTelephonyManager() {
203 if (mTelephonyManager == null) {
204 mTelephonyManager = (TelephonyManager) mContext.getSystemService(
205 Context.TELEPHONY_SERVICE);
206 }
207 return mTelephonyManager;
208 }
209
210 /*
211 * Throws a security exception unless the caller has carrier privilege.
212 */
213 private void enforceCarrierPrivilege() {
Ye Wenbdc3a462014-11-11 11:17:28 -0800214 final String[] packages = getPackageManager().getPackagesForUid(Binder.getCallingUid());
Ye Wend97e1fd2014-07-24 12:56:45 -0700215 for (String pkg : packages) {
216 if (getTelephonyManager().checkCarrierPrivilegesForPackage(pkg) ==
217 TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
218 return;
219 }
220 }
221 throw new SecurityException("No carrier privilege");
222 }
223
Ye Wenbdc3a462014-11-11 11:17:28 -0800224 private String getCallingPackageName() {
225 final String[] packages = getPackageManager().getPackagesForUid(Binder.getCallingUid());
226 if (packages != null && packages.length > 0) {
227 return packages[0];
228 }
229 return "unknown";
230 }
231
Ye Wend97e1fd2014-07-24 12:56:45 -0700232 // Service API calls implementation, proxied to the real MmsService in "com.android.mms.service"
233 private final class BinderService extends IMms.Stub {
Tom Taylor86201db2014-11-24 09:36:43 -0800234 private static final String PHONE_PACKAGE_NAME = "com.android.phone";
235
Ye Wend97e1fd2014-07-24 12:56:45 -0700236 @Override
Wink Saville63f03dd2014-10-23 10:44:45 -0700237 public void sendMessage(int subId, String callingPkg, Uri contentUri,
Ye Wen8179c2a2014-09-04 15:36:11 -0700238 String locationUrl, Bundle configOverrides, PendingIntent sentIntent)
Julian Odell31ef14d2014-08-25 17:53:52 -0700239 throws RemoteException {
Ye Wenbdc3a462014-11-11 11:17:28 -0800240 Slog.d(TAG, "sendMessage() by " + callingPkg);
Ye Wend97e1fd2014-07-24 12:56:45 -0700241 mContext.enforceCallingPermission(Manifest.permission.SEND_SMS, "Send MMS message");
242 if (getAppOpsManager().noteOp(AppOpsManager.OP_SEND_SMS, Binder.getCallingUid(),
243 callingPkg) != AppOpsManager.MODE_ALLOWED) {
244 return;
245 }
Tom Taylor86201db2014-11-24 09:36:43 -0800246 contentUri = adjustUriForUserAndGrantPermission(contentUri,
247 Telephony.Mms.Intents.MMS_SEND_ACTION,
248 Intent.FLAG_GRANT_READ_URI_PERMISSION);
Julian Odell31ef14d2014-08-25 17:53:52 -0700249 getServiceGuarded().sendMessage(subId, callingPkg, contentUri, locationUrl,
250 configOverrides, sentIntent);
Ye Wend97e1fd2014-07-24 12:56:45 -0700251 }
252
253 @Override
Wink Saville63f03dd2014-10-23 10:44:45 -0700254 public void downloadMessage(int subId, String callingPkg, String locationUrl,
Ye Wen8179c2a2014-09-04 15:36:11 -0700255 Uri contentUri, Bundle configOverrides,
Julian Odell31ef14d2014-08-25 17:53:52 -0700256 PendingIntent downloadedIntent) throws RemoteException {
Ye Wenbdc3a462014-11-11 11:17:28 -0800257 Slog.d(TAG, "downloadMessage() by " + callingPkg);
Ye Wend97e1fd2014-07-24 12:56:45 -0700258 mContext.enforceCallingPermission(Manifest.permission.RECEIVE_MMS,
259 "Download MMS message");
260 if (getAppOpsManager().noteOp(AppOpsManager.OP_RECEIVE_MMS, Binder.getCallingUid(),
261 callingPkg) != AppOpsManager.MODE_ALLOWED) {
262 return;
263 }
Tom Taylor86201db2014-11-24 09:36:43 -0800264 contentUri = adjustUriForUserAndGrantPermission(contentUri,
265 Telephony.Mms.Intents.MMS_DOWNLOAD_ACTION,
266 Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
267
Julian Odell31ef14d2014-08-25 17:53:52 -0700268 getServiceGuarded().downloadMessage(subId, callingPkg, locationUrl, contentUri,
269 configOverrides, downloadedIntent);
Ye Wend97e1fd2014-07-24 12:56:45 -0700270 }
271
272 @Override
Cheuksan Wangee045432014-09-08 19:54:58 -0700273 public void updateMmsSendStatus(int messageRef, byte[] pdu, int status)
274 throws RemoteException {
Ye Wend97e1fd2014-07-24 12:56:45 -0700275 enforceCarrierPrivilege();
Cheuksan Wangee045432014-09-08 19:54:58 -0700276 getServiceGuarded().updateMmsSendStatus(messageRef, pdu, status);
Ye Wend97e1fd2014-07-24 12:56:45 -0700277 }
278
279 @Override
Cheuksan Wangee045432014-09-08 19:54:58 -0700280 public void updateMmsDownloadStatus(int messageRef, int status) throws RemoteException {
Ye Wend97e1fd2014-07-24 12:56:45 -0700281 enforceCarrierPrivilege();
Cheuksan Wangee045432014-09-08 19:54:58 -0700282 getServiceGuarded().updateMmsDownloadStatus(messageRef, status);
Ye Wend97e1fd2014-07-24 12:56:45 -0700283 }
284
285 @Override
Wink Saville63f03dd2014-10-23 10:44:45 -0700286 public Bundle getCarrierConfigValues(int subId) throws RemoteException {
Ye Wenbdc3a462014-11-11 11:17:28 -0800287 Slog.d(TAG, "getCarrierConfigValues() by " + getCallingPackageName());
Shri Borde72379722014-09-02 09:48:49 -0700288 return getServiceGuarded().getCarrierConfigValues(subId);
Ye Wend97e1fd2014-07-24 12:56:45 -0700289 }
290
291 @Override
292 public Uri importTextMessage(String callingPkg, String address, int type, String text,
293 long timestampMillis, boolean seen, boolean read) throws RemoteException {
294 mContext.enforceCallingPermission(Manifest.permission.WRITE_SMS, "Import SMS message");
295 if (getAppOpsManager().noteOp(AppOpsManager.OP_WRITE_SMS, Binder.getCallingUid(),
296 callingPkg) != AppOpsManager.MODE_ALLOWED) {
Ye Wenfa58ac02014-07-31 17:15:30 -0700297 // Silently fail AppOps failure due to not being the default SMS app
298 // while writing the TelephonyProvider
299 return FAKE_SMS_SENT_URI;
Ye Wend97e1fd2014-07-24 12:56:45 -0700300 }
301 return getServiceGuarded().importTextMessage(
302 callingPkg, address, type, text, timestampMillis, seen, read);
303 }
304
305 @Override
Julian Odell31ef14d2014-08-25 17:53:52 -0700306 public Uri importMultimediaMessage(String callingPkg, Uri contentUri,
307 String messageId, long timestampSecs, boolean seen, boolean read)
308 throws RemoteException {
Ye Wend97e1fd2014-07-24 12:56:45 -0700309 mContext.enforceCallingPermission(Manifest.permission.WRITE_SMS, "Import MMS message");
310 if (getAppOpsManager().noteOp(AppOpsManager.OP_WRITE_SMS, Binder.getCallingUid(),
311 callingPkg) != AppOpsManager.MODE_ALLOWED) {
Ye Wenfa58ac02014-07-31 17:15:30 -0700312 // Silently fail AppOps failure due to not being the default SMS app
313 // while writing the TelephonyProvider
314 return FAKE_MMS_SENT_URI;
Ye Wend97e1fd2014-07-24 12:56:45 -0700315 }
316 return getServiceGuarded().importMultimediaMessage(
Julian Odell31ef14d2014-08-25 17:53:52 -0700317 callingPkg, contentUri, messageId, timestampSecs, seen, read);
Ye Wend97e1fd2014-07-24 12:56:45 -0700318 }
319
320 @Override
321 public boolean deleteStoredMessage(String callingPkg, Uri messageUri)
322 throws RemoteException {
323 mContext.enforceCallingPermission(Manifest.permission.WRITE_SMS,
324 "Delete SMS/MMS message");
325 if (getAppOpsManager().noteOp(AppOpsManager.OP_WRITE_SMS, Binder.getCallingUid(),
326 callingPkg) != AppOpsManager.MODE_ALLOWED) {
327 return false;
328 }
329 return getServiceGuarded().deleteStoredMessage(callingPkg, messageUri);
330 }
331
332 @Override
333 public boolean deleteStoredConversation(String callingPkg, long conversationId)
334 throws RemoteException {
335 mContext.enforceCallingPermission(Manifest.permission.WRITE_SMS, "Delete conversation");
336 if (getAppOpsManager().noteOp(AppOpsManager.OP_WRITE_SMS, Binder.getCallingUid(),
337 callingPkg) != AppOpsManager.MODE_ALLOWED) {
338 return false;
339 }
340 return getServiceGuarded().deleteStoredConversation(callingPkg, conversationId);
341 }
342
343 @Override
344 public boolean updateStoredMessageStatus(String callingPkg, Uri messageUri,
345 ContentValues statusValues) throws RemoteException {
346 mContext.enforceCallingPermission(Manifest.permission.WRITE_SMS,
347 "Update SMS/MMS message");
348 return getServiceGuarded()
349 .updateStoredMessageStatus(callingPkg, messageUri, statusValues);
350 }
351
352 @Override
Ye Wena3dbd102014-07-29 10:42:25 -0700353 public boolean archiveStoredConversation(String callingPkg, long conversationId,
354 boolean archived) throws RemoteException {
355 mContext.enforceCallingPermission(Manifest.permission.WRITE_SMS,
356 "Update SMS/MMS message");
357 return getServiceGuarded()
358 .archiveStoredConversation(callingPkg, conversationId, archived);
359 }
360
361 @Override
Ye Wend97e1fd2014-07-24 12:56:45 -0700362 public Uri addTextMessageDraft(String callingPkg, String address, String text)
363 throws RemoteException {
364 mContext.enforceCallingPermission(Manifest.permission.WRITE_SMS, "Add SMS draft");
365 if (getAppOpsManager().noteOp(AppOpsManager.OP_WRITE_SMS, Binder.getCallingUid(),
366 callingPkg) != AppOpsManager.MODE_ALLOWED) {
Ye Wenfa58ac02014-07-31 17:15:30 -0700367 // Silently fail AppOps failure due to not being the default SMS app
368 // while writing the TelephonyProvider
369 return FAKE_SMS_DRAFT_URI;
Ye Wend97e1fd2014-07-24 12:56:45 -0700370 }
371 return getServiceGuarded().addTextMessageDraft(callingPkg, address, text);
372 }
373
374 @Override
Julian Odell31ef14d2014-08-25 17:53:52 -0700375 public Uri addMultimediaMessageDraft(String callingPkg, Uri contentUri)
376 throws RemoteException {
Ye Wend97e1fd2014-07-24 12:56:45 -0700377 mContext.enforceCallingPermission(Manifest.permission.WRITE_SMS, "Add MMS draft");
378 if (getAppOpsManager().noteOp(AppOpsManager.OP_WRITE_SMS, Binder.getCallingUid(),
379 callingPkg) != AppOpsManager.MODE_ALLOWED) {
Ye Wenfa58ac02014-07-31 17:15:30 -0700380 // Silently fail AppOps failure due to not being the default SMS app
381 // while writing the TelephonyProvider
382 return FAKE_MMS_DRAFT_URI;
Ye Wend97e1fd2014-07-24 12:56:45 -0700383 }
Julian Odell31ef14d2014-08-25 17:53:52 -0700384 return getServiceGuarded().addMultimediaMessageDraft(callingPkg, contentUri);
Ye Wend97e1fd2014-07-24 12:56:45 -0700385 }
386
387 @Override
Wink Saville63f03dd2014-10-23 10:44:45 -0700388 public void sendStoredMessage(int subId, String callingPkg, Uri messageUri,
Ye Wen8179c2a2014-09-04 15:36:11 -0700389 Bundle configOverrides, PendingIntent sentIntent) throws RemoteException {
Ye Wend97e1fd2014-07-24 12:56:45 -0700390 mContext.enforceCallingPermission(Manifest.permission.SEND_SMS,
391 "Send stored MMS message");
392 if (getAppOpsManager().noteOp(AppOpsManager.OP_SEND_SMS, Binder.getCallingUid(),
393 callingPkg) != AppOpsManager.MODE_ALLOWED) {
394 return;
395 }
Ye Wen63c00c42014-08-01 13:38:58 -0700396 getServiceGuarded().sendStoredMessage(subId, callingPkg, messageUri, configOverrides,
397 sentIntent);
Ye Wend97e1fd2014-07-24 12:56:45 -0700398 }
399
400 @Override
401 public void setAutoPersisting(String callingPkg, boolean enabled) throws RemoteException {
402 mContext.enforceCallingPermission(Manifest.permission.WRITE_SMS, "Set auto persist");
403 if (getAppOpsManager().noteOp(AppOpsManager.OP_WRITE_SMS, Binder.getCallingUid(),
404 callingPkg) != AppOpsManager.MODE_ALLOWED) {
405 return;
406 }
407 getServiceGuarded().setAutoPersisting(callingPkg, enabled);
408 }
409
410 @Override
411 public boolean getAutoPersisting() throws RemoteException {
412 return getServiceGuarded().getAutoPersisting();
413 }
Tom Taylor86201db2014-11-24 09:36:43 -0800414
415 /**
416 * Modifies the Uri to contain the caller's userId, if necessary.
417 * Grants the phone package on primary user permission to access the contentUri,
418 * even if the caller is not in the primary user.
419 *
420 * @param contentUri The Uri to adjust
421 * @param action The intent action used to find the associated carrier app
422 * @param permission The permission to add
423 * @return The adjusted Uri containing the calling userId.
424 */
425 private Uri adjustUriForUserAndGrantPermission(Uri contentUri, String action,
426 int permission) {
427 final int callingUserId = UserHandle.getCallingUserId();
428 if (callingUserId != UserHandle.USER_OWNER) {
429 contentUri = ContentProvider.maybeAddUserId(contentUri, callingUserId);
430 }
431 long token = Binder.clearCallingIdentity();
432 try {
433 mContext.grantUriPermission(PHONE_PACKAGE_NAME, contentUri, permission);
434
435 // Grant permission for the carrier app.
436 Intent intent = new Intent(action);
437 TelephonyManager telephonyManager =
438 (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
439 List<String> carrierPackages = telephonyManager.getCarrierPackageNamesForIntent(
440 intent);
441 if (carrierPackages != null && carrierPackages.size() == 1) {
442 mContext.grantUriPermission(carrierPackages.get(0), contentUri, permission);
443 }
444 } finally {
445 Binder.restoreCallingIdentity(token);
446 }
447 return contentUri;
448 }
Ye Wend97e1fd2014-07-24 12:56:45 -0700449 }
450}