VoiceInteractionManagerService.java revision d7018200312e4e4dc3f67cf33dc90bf7ce585844
1/* 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.voiceinteraction; 18 19import android.Manifest; 20import android.app.ActivityManager; 21import android.content.ComponentName; 22import android.content.ContentResolver; 23import android.content.Context; 24import android.content.Intent; 25import android.content.pm.PackageManager; 26import android.database.ContentObserver; 27import android.hardware.soundtrigger.KeyphraseSoundModel; 28import android.os.Binder; 29import android.os.Bundle; 30import android.os.Handler; 31import android.os.IBinder; 32import android.os.Parcel; 33import android.os.RemoteException; 34import android.os.UserHandle; 35import android.provider.Settings; 36import android.service.voice.IVoiceInteractionService; 37import android.service.voice.IVoiceInteractionSession; 38import android.util.Slog; 39 40import com.android.internal.app.IVoiceInteractionManagerService; 41import com.android.internal.app.IVoiceInteractor; 42import com.android.internal.content.PackageMonitor; 43import com.android.internal.os.BackgroundThread; 44import com.android.server.SystemService; 45import com.android.server.UiThread; 46 47import java.io.FileDescriptor; 48import java.io.PrintWriter; 49import java.util.List; 50 51 52/** 53 * SystemService that publishes an IVoiceInteractionManagerService. 54 */ 55public class VoiceInteractionManagerService extends SystemService { 56 57 static final String TAG = "VoiceInteractionManagerService"; 58 59 // TODO: Add descriptive error codes. 60 public static final int STATUS_ERROR = -1; 61 public static final int STATUS_OK = 1; 62 63 final Context mContext; 64 final ContentResolver mResolver; 65 66 public VoiceInteractionManagerService(Context context) { 67 super(context); 68 mContext = context; 69 mResolver = context.getContentResolver(); 70 } 71 72 @Override 73 public void onStart() { 74 publishBinderService(Context.VOICE_INTERACTION_MANAGER_SERVICE, mServiceStub); 75 } 76 77 @Override 78 public void onBootPhase(int phase) { 79 if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) { 80 mServiceStub.systemRunning(isSafeMode()); 81 } 82 } 83 84 @Override 85 public void onSwitchUser(int userHandle) { 86 mServiceStub.switchUser(userHandle); 87 } 88 89 // implementation entry point and binder service 90 private final VoiceInteractionManagerServiceStub mServiceStub 91 = new VoiceInteractionManagerServiceStub(); 92 93 class VoiceInteractionManagerServiceStub extends IVoiceInteractionManagerService.Stub { 94 95 VoiceInteractionManagerServiceImpl mImpl; 96 97 private boolean mSafeMode; 98 private int mCurUser; 99 100 @Override 101 public boolean onTransact(int code, Parcel data, Parcel reply, int flags) 102 throws RemoteException { 103 try { 104 return super.onTransact(code, data, reply, flags); 105 } catch (RuntimeException e) { 106 // The activity manager only throws security exceptions, so let's 107 // log all others. 108 if (!(e instanceof SecurityException)) { 109 Slog.wtf(TAG, "VoiceInteractionManagerService Crash", e); 110 } 111 throw e; 112 } 113 } 114 115 public void systemRunning(boolean safeMode) { 116 mSafeMode = safeMode; 117 118 mPackageMonitor.register(mContext, BackgroundThread.getHandler().getLooper(), 119 UserHandle.ALL, true); 120 new SettingsObserver(UiThread.getHandler()); 121 122 synchronized (this) { 123 mCurUser = ActivityManager.getCurrentUser(); 124 switchImplementationIfNeededLocked(false); 125 } 126 } 127 128 public void switchUser(int userHandle) { 129 synchronized (this) { 130 mCurUser = userHandle; 131 switchImplementationIfNeededLocked(false); 132 } 133 } 134 135 void switchImplementationIfNeededLocked(boolean force) { 136 if (!mSafeMode) { 137 String curService = Settings.Secure.getStringForUser( 138 mResolver, Settings.Secure.VOICE_INTERACTION_SERVICE, mCurUser); 139 ComponentName serviceComponent = null; 140 if (curService != null && !curService.isEmpty()) { 141 try { 142 serviceComponent = ComponentName.unflattenFromString(curService); 143 } catch (RuntimeException e) { 144 Slog.wtf(TAG, "Bad voice interaction service name " + curService, e); 145 serviceComponent = null; 146 } 147 } 148 if (force || mImpl == null || mImpl.mUser != mCurUser 149 || !mImpl.mComponent.equals(serviceComponent)) { 150 if (mImpl != null) { 151 mImpl.shutdownLocked(); 152 } 153 if (serviceComponent != null) { 154 mImpl = new VoiceInteractionManagerServiceImpl(mContext, 155 UiThread.getHandler(), this, mCurUser, serviceComponent); 156 mImpl.startLocked(); 157 } else { 158 mImpl = null; 159 } 160 } 161 } 162 } 163 164 @Override 165 public void startSession(IVoiceInteractionService service, Bundle args) { 166 synchronized (this) { 167 if (mImpl == null || mImpl.mService == null 168 || service.asBinder() != mImpl.mService.asBinder()) { 169 throw new SecurityException( 170 "Caller is not the current voice interaction service"); 171 } 172 final int callingPid = Binder.getCallingPid(); 173 final int callingUid = Binder.getCallingUid(); 174 final long caller = Binder.clearCallingIdentity(); 175 try { 176 mImpl.startSessionLocked(callingPid, callingUid, args); 177 } finally { 178 Binder.restoreCallingIdentity(caller); 179 } 180 } 181 } 182 183 @Override 184 public boolean deliverNewSession(IBinder token, IVoiceInteractionSession session, 185 IVoiceInteractor interactor) { 186 synchronized (this) { 187 if (mImpl == null) { 188 throw new SecurityException( 189 "deliverNewSession without running voice interaction service"); 190 } 191 final int callingPid = Binder.getCallingPid(); 192 final int callingUid = Binder.getCallingUid(); 193 final long caller = Binder.clearCallingIdentity(); 194 try { 195 return mImpl.deliverNewSessionLocked(callingPid, callingUid, token, session, 196 interactor); 197 } finally { 198 Binder.restoreCallingIdentity(caller); 199 } 200 } 201 } 202 203 @Override 204 public int startVoiceActivity(IBinder token, Intent intent, String resolvedType) { 205 synchronized (this) { 206 if (mImpl == null) { 207 Slog.w(TAG, "startVoiceActivity without running voice interaction service"); 208 return ActivityManager.START_CANCELED; 209 } 210 final int callingPid = Binder.getCallingPid(); 211 final int callingUid = Binder.getCallingUid(); 212 final long caller = Binder.clearCallingIdentity(); 213 try { 214 return mImpl.startVoiceActivityLocked(callingPid, callingUid, token, 215 intent, resolvedType); 216 } finally { 217 Binder.restoreCallingIdentity(caller); 218 } 219 } 220 } 221 222 @Override 223 public void finish(IBinder token) { 224 synchronized (this) { 225 if (mImpl == null) { 226 Slog.w(TAG, "finish without running voice interaction service"); 227 return; 228 } 229 final int callingPid = Binder.getCallingPid(); 230 final int callingUid = Binder.getCallingUid(); 231 final long caller = Binder.clearCallingIdentity(); 232 try { 233 mImpl.finishLocked(callingPid, callingUid, token); 234 } finally { 235 Binder.restoreCallingIdentity(caller); 236 } 237 } 238 } 239 240 @Override 241 public List<KeyphraseSoundModel> listRegisteredKeyphraseSoundModels( 242 IVoiceInteractionService service) { 243 // Allow the call if this is the current voice interaction service 244 // or the caller holds the MANAGE_VOICE_KEYPHRASES permission. 245 synchronized (this) { 246 boolean permissionGranted = 247 mContext.checkCallingPermission(Manifest.permission.MANAGE_VOICE_KEYPHRASES) 248 == PackageManager.PERMISSION_GRANTED; 249 boolean currentVoiceInteractionService = service != null 250 && mImpl != null 251 && mImpl.mService != null 252 && service.asBinder() == mImpl.mService.asBinder(); 253 254 if (!permissionGranted && !currentVoiceInteractionService) { 255 if (!currentVoiceInteractionService) { 256 throw new SecurityException( 257 "Caller is not the current voice interaction service"); 258 } 259 if (!permissionGranted) { 260 throw new SecurityException("Caller does not hold the permission " 261 + Manifest.permission.MANAGE_VOICE_KEYPHRASES); 262 } 263 } 264 265 final long caller = Binder.clearCallingIdentity(); 266 try { 267 // TODO: Add the implementation here. 268 return null; 269 } finally { 270 Binder.restoreCallingIdentity(caller); 271 } 272 } 273 } 274 275 @Override 276 public int updateKeyphraseSoundModel(KeyphraseSoundModel model) { 277 synchronized (this) { 278 if (mContext.checkCallingPermission(Manifest.permission.MANAGE_VOICE_KEYPHRASES) 279 != PackageManager.PERMISSION_GRANTED) { 280 throw new SecurityException("Caller does not hold the permission " 281 + Manifest.permission.MANAGE_VOICE_KEYPHRASES); 282 } 283 final long caller = Binder.clearCallingIdentity(); 284 try { 285 // TODO: Add the implementation here. 286 return VoiceInteractionManagerService.STATUS_ERROR; 287 } finally { 288 Binder.restoreCallingIdentity(caller); 289 } 290 } 291 } 292 293 @Override 294 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 295 if (mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP) 296 != PackageManager.PERMISSION_GRANTED) { 297 pw.println("Permission Denial: can't dump PowerManager from from pid=" 298 + Binder.getCallingPid() 299 + ", uid=" + Binder.getCallingUid()); 300 return; 301 } 302 synchronized (this) { 303 pw.println("VOICE INTERACTION MANAGER (dumpsys voiceinteraction)\n"); 304 if (mImpl == null) { 305 pw.println(" (No active implementation)"); 306 return; 307 } 308 mImpl.dumpLocked(fd, pw, args); 309 } 310 } 311 312 class SettingsObserver extends ContentObserver { 313 SettingsObserver(Handler handler) { 314 super(handler); 315 ContentResolver resolver = mContext.getContentResolver(); 316 resolver.registerContentObserver(Settings.Secure.getUriFor( 317 Settings.Secure.VOICE_INTERACTION_SERVICE), false, this); 318 } 319 320 @Override public void onChange(boolean selfChange) { 321 synchronized (VoiceInteractionManagerServiceStub.this) { 322 switchImplementationIfNeededLocked(false); 323 } 324 } 325 } 326 327 PackageMonitor mPackageMonitor = new PackageMonitor() { 328 @Override 329 public boolean onHandleForceStop(Intent intent, String[] packages, int uid, boolean doit) { 330 return super.onHandleForceStop(intent, packages, uid, doit); 331 } 332 333 @Override 334 public void onHandleUserStop(Intent intent, int userHandle) { 335 } 336 337 @Override 338 public void onPackageDisappeared(String packageName, int reason) { 339 } 340 341 @Override 342 public void onPackageAppeared(String packageName, int reason) { 343 if (mImpl != null && packageName.equals(mImpl.mComponent.getPackageName())) { 344 switchImplementationIfNeededLocked(true); 345 } 346 } 347 348 @Override 349 public void onPackageModified(String packageName) { 350 } 351 352 @Override 353 public void onSomePackagesChanged() { 354 } 355 }; 356 } 357} 358