VoiceInteractionManagerService.java revision b835dd7641c60cd5d2b372331ffc19f7165244bd
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.app.AppGlobals; 22import android.content.ComponentName; 23import android.content.ContentResolver; 24import android.content.Context; 25import android.content.Intent; 26import android.content.pm.ApplicationInfo; 27import android.content.pm.IPackageManager; 28import android.content.pm.PackageManager; 29import android.content.pm.ResolveInfo; 30import android.content.pm.ServiceInfo; 31import android.content.res.Resources; 32import android.database.ContentObserver; 33import android.hardware.soundtrigger.IRecognitionStatusCallback; 34import android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel; 35import android.hardware.soundtrigger.SoundTrigger.ModuleProperties; 36import android.hardware.soundtrigger.SoundTrigger.RecognitionConfig; 37import android.os.Binder; 38import android.os.Bundle; 39import android.os.Handler; 40import android.os.IBinder; 41import android.os.Parcel; 42import android.os.RemoteException; 43import android.os.UserHandle; 44import android.provider.Settings; 45import android.service.voice.IVoiceInteractionService; 46import android.service.voice.IVoiceInteractionSession; 47import android.service.voice.VoiceInteractionService; 48import android.service.voice.VoiceInteractionServiceInfo; 49import android.service.voice.VoiceInteractionSession; 50import android.speech.RecognitionService; 51import android.text.TextUtils; 52import android.util.Log; 53import android.util.Slog; 54 55import com.android.internal.app.IVoiceInteractionManagerService; 56import com.android.internal.app.IVoiceInteractionSessionShowCallback; 57import com.android.internal.app.IVoiceInteractor; 58import com.android.internal.content.PackageMonitor; 59import com.android.internal.os.BackgroundThread; 60import com.android.server.SystemService; 61import com.android.server.UiThread; 62 63import java.io.FileDescriptor; 64import java.io.PrintWriter; 65import java.util.List; 66 67/** 68 * SystemService that publishes an IVoiceInteractionManagerService. 69 */ 70public class VoiceInteractionManagerService extends SystemService { 71 static final String TAG = "VoiceInteractionManagerService"; 72 static final boolean DEBUG = false; 73 74 final Context mContext; 75 final ContentResolver mResolver; 76 final DatabaseHelper mDbHelper; 77 final SoundTriggerHelper mSoundTriggerHelper; 78 79 public VoiceInteractionManagerService(Context context) { 80 super(context); 81 mContext = context; 82 mResolver = context.getContentResolver(); 83 mDbHelper = new DatabaseHelper(context); 84 mSoundTriggerHelper = new SoundTriggerHelper(context); 85 mServiceStub = new VoiceInteractionManagerServiceStub(); 86 } 87 88 @Override 89 public void onStart() { 90 publishBinderService(Context.VOICE_INTERACTION_MANAGER_SERVICE, mServiceStub); 91 } 92 93 @Override 94 public void onBootPhase(int phase) { 95 if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) { 96 mServiceStub.systemRunning(isSafeMode()); 97 } 98 } 99 100 @Override 101 public void onStartUser(int userHandle) { 102 mServiceStub.initForUser(userHandle); 103 } 104 105 @Override 106 public void onSwitchUser(int userHandle) { 107 mServiceStub.switchUser(userHandle); 108 } 109 110 // implementation entry point and binder service 111 private final VoiceInteractionManagerServiceStub mServiceStub; 112 113 class VoiceInteractionManagerServiceStub extends IVoiceInteractionManagerService.Stub { 114 115 VoiceInteractionManagerServiceImpl mImpl; 116 117 private boolean mSafeMode; 118 private int mCurUser; 119 private final boolean mEnableService; 120 121 VoiceInteractionManagerServiceStub() { 122 mEnableService = shouldEnableService(mContext.getResources()); 123 } 124 125 @Override 126 public boolean onTransact(int code, Parcel data, Parcel reply, int flags) 127 throws RemoteException { 128 try { 129 return super.onTransact(code, data, reply, flags); 130 } catch (RuntimeException e) { 131 // The activity manager only throws security exceptions, so let's 132 // log all others. 133 if (!(e instanceof SecurityException)) { 134 Slog.wtf(TAG, "VoiceInteractionManagerService Crash", e); 135 } 136 throw e; 137 } 138 } 139 140 public void initForUser(int userHandle) { 141 if (DEBUG) Slog.d(TAG, "**************** initForUser user=" + userHandle); 142 String curInteractorStr = Settings.Secure.getStringForUser( 143 mContext.getContentResolver(), 144 Settings.Secure.VOICE_INTERACTION_SERVICE, userHandle); 145 ComponentName curRecognizer = getCurRecognizer(userHandle); 146 VoiceInteractionServiceInfo curInteractorInfo = null; 147 if (DEBUG) Slog.d(TAG, "curInteractorStr=" + curInteractorStr 148 + " curRecognizer=" + curRecognizer); 149 if (curInteractorStr == null && curRecognizer != null && mEnableService) { 150 // If there is no interactor setting, that means we are upgrading 151 // from an older platform version. If the current recognizer is not 152 // set or matches the preferred recognizer, then we want to upgrade 153 // the user to have the default voice interaction service enabled. 154 // Note that we don't do this for low-RAM devices, since we aren't 155 // supporting voice interaction services there. 156 curInteractorInfo = findAvailInteractor(userHandle, curRecognizer.getPackageName()); 157 if (curInteractorInfo != null) { 158 // Looks good! We'll apply this one. To make it happen, we clear the 159 // recognizer so that we don't think we have anything set and will 160 // re-apply the settings. 161 if (DEBUG) Slog.d(TAG, "No set interactor, found avail: " 162 + curInteractorInfo.getServiceInfo().name); 163 curRecognizer = null; 164 } 165 } 166 167 // If forceInteractorPackage exists, try to apply the interactor from this package if 168 // possible and ignore the regular interactor setting. 169 String forceInteractorPackage = 170 getForceVoiceInteractionServicePackage(mContext.getResources()); 171 if (forceInteractorPackage != null) { 172 curInteractorInfo = findAvailInteractor(userHandle, forceInteractorPackage); 173 if (curInteractorInfo != null) { 174 // We'll apply this one. Clear the recognizer and re-apply the settings. 175 curRecognizer = null; 176 } 177 } 178 179 // If we are on a svelte device, make sure an interactor is not currently 180 // enabled; if it is, turn it off. 181 if (!mEnableService && curInteractorStr != null) { 182 if (!TextUtils.isEmpty(curInteractorStr)) { 183 if (DEBUG) Slog.d(TAG, "Svelte device; disabling interactor"); 184 setCurInteractor(null, userHandle); 185 curInteractorStr = ""; 186 } 187 } 188 189 if (curRecognizer != null) { 190 // If we already have at least a recognizer, then we probably want to 191 // leave things as they are... unless something has disappeared. 192 IPackageManager pm = AppGlobals.getPackageManager(); 193 ServiceInfo interactorInfo = null; 194 ServiceInfo recognizerInfo = null; 195 ComponentName curInteractor = !TextUtils.isEmpty(curInteractorStr) 196 ? ComponentName.unflattenFromString(curInteractorStr) : null; 197 try { 198 recognizerInfo = pm.getServiceInfo(curRecognizer, 0, userHandle); 199 if (curInteractor != null) { 200 interactorInfo = pm.getServiceInfo(curInteractor, 0, userHandle); 201 } 202 } catch (RemoteException e) { 203 } 204 // If the apps for the currently set components still exist, then all is okay. 205 if (recognizerInfo != null && (curInteractor == null || interactorInfo != null)) { 206 if (DEBUG) Slog.d(TAG, "Current interactor/recognizer okay, done!"); 207 return; 208 } 209 if (DEBUG) Slog.d(TAG, "Bad recognizer (" + recognizerInfo + ") or interactor (" 210 + interactorInfo + ")"); 211 } 212 213 // Initializing settings, look for an interactor first (but only on non-svelte). 214 if (curInteractorInfo == null && mEnableService) { 215 curInteractorInfo = findAvailInteractor(userHandle, null); 216 } 217 218 if (curInteractorInfo != null) { 219 // Eventually it will be an error to not specify this. 220 setCurInteractor(new ComponentName(curInteractorInfo.getServiceInfo().packageName, 221 curInteractorInfo.getServiceInfo().name), userHandle); 222 if (curInteractorInfo.getRecognitionService() != null) { 223 setCurRecognizer( 224 new ComponentName(curInteractorInfo.getServiceInfo().packageName, 225 curInteractorInfo.getRecognitionService()), userHandle); 226 return; 227 } 228 } 229 230 // No voice interactor, we'll just set up a simple recognizer. 231 curRecognizer = findAvailRecognizer(null, userHandle); 232 if (curRecognizer != null) { 233 if (curInteractorInfo == null) { 234 setCurInteractor(null, userHandle); 235 } 236 setCurRecognizer(curRecognizer, userHandle); 237 } 238 } 239 240 private boolean shouldEnableService(Resources res) { 241 // VoiceInteractionService should not be enabled on low ram devices unless it has the config flag. 242 return !ActivityManager.isLowRamDeviceStatic() || 243 getForceVoiceInteractionServicePackage(res) != null; 244 } 245 246 private String getForceVoiceInteractionServicePackage(Resources res) { 247 String interactorPackage = 248 res.getString(com.android.internal.R.string.config_forceVoiceInteractionServicePackage); 249 return TextUtils.isEmpty(interactorPackage) ? null : interactorPackage; 250 } 251 252 public void systemRunning(boolean safeMode) { 253 mSafeMode = safeMode; 254 255 mPackageMonitor.register(mContext, BackgroundThread.getHandler().getLooper(), 256 UserHandle.ALL, true); 257 new SettingsObserver(UiThread.getHandler()); 258 259 synchronized (this) { 260 mCurUser = ActivityManager.getCurrentUser(); 261 switchImplementationIfNeededLocked(false); 262 } 263 } 264 265 public void switchUser(int userHandle) { 266 synchronized (this) { 267 mCurUser = userHandle; 268 switchImplementationIfNeededLocked(false); 269 } 270 } 271 272 void switchImplementationIfNeededLocked(boolean force) { 273 if (!mSafeMode) { 274 String curService = Settings.Secure.getStringForUser( 275 mResolver, Settings.Secure.VOICE_INTERACTION_SERVICE, mCurUser); 276 ComponentName serviceComponent = null; 277 if (curService != null && !curService.isEmpty()) { 278 try { 279 serviceComponent = ComponentName.unflattenFromString(curService); 280 } catch (RuntimeException e) { 281 Slog.wtf(TAG, "Bad voice interaction service name " + curService, e); 282 serviceComponent = null; 283 } 284 } 285 if (force || mImpl == null || mImpl.mUser != mCurUser 286 || !mImpl.mComponent.equals(serviceComponent)) { 287 mSoundTriggerHelper.stopAllRecognitions(); 288 if (mImpl != null) { 289 mImpl.shutdownLocked(); 290 } 291 if (serviceComponent != null) { 292 mImpl = new VoiceInteractionManagerServiceImpl(mContext, 293 UiThread.getHandler(), this, mCurUser, serviceComponent); 294 mImpl.startLocked(); 295 } else { 296 mImpl = null; 297 } 298 } 299 } 300 } 301 302 VoiceInteractionServiceInfo findAvailInteractor(int userHandle, String packageName) { 303 List<ResolveInfo> available = 304 mContext.getPackageManager().queryIntentServicesAsUser( 305 new Intent(VoiceInteractionService.SERVICE_INTERFACE), 0, userHandle); 306 int numAvailable = available.size(); 307 308 if (numAvailable == 0) { 309 Slog.w(TAG, "no available voice interaction services found for user " + userHandle); 310 return null; 311 } else { 312 // Find first system package. We never want to allow third party services to 313 // be automatically selected, because those require approval of the user. 314 VoiceInteractionServiceInfo foundInfo = null; 315 for (int i=0; i<numAvailable; i++) { 316 ServiceInfo cur = available.get(i).serviceInfo; 317 if ((cur.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) != 0) { 318 ComponentName comp = new ComponentName(cur.packageName, cur.name); 319 try { 320 VoiceInteractionServiceInfo info = new VoiceInteractionServiceInfo( 321 mContext.getPackageManager(), comp, userHandle); 322 if (info.getParseError() == null) { 323 if (packageName == null || info.getServiceInfo().packageName.equals( 324 packageName)) { 325 if (foundInfo == null) { 326 foundInfo = info; 327 } else { 328 Slog.w(TAG, "More than one voice interaction service, " 329 + "picking first " 330 + new ComponentName( 331 foundInfo.getServiceInfo().packageName, 332 foundInfo.getServiceInfo().name) 333 + " over " 334 + new ComponentName(cur.packageName, cur.name)); 335 } 336 } 337 } else { 338 Slog.w(TAG, "Bad interaction service " + comp + ": " 339 + info.getParseError()); 340 } 341 } catch (PackageManager.NameNotFoundException e) { 342 Slog.w(TAG, "Failure looking up interaction service " + comp); 343 } catch (RemoteException e) { 344 } 345 } 346 } 347 348 return foundInfo; 349 } 350 } 351 352 ComponentName getCurInteractor(int userHandle) { 353 String curInteractor = Settings.Secure.getStringForUser( 354 mContext.getContentResolver(), 355 Settings.Secure.VOICE_INTERACTION_SERVICE, userHandle); 356 if (TextUtils.isEmpty(curInteractor)) { 357 return null; 358 } 359 if (DEBUG) Slog.d(TAG, "getCurInteractor curInteractor=" + curInteractor 360 + " user=" + userHandle); 361 return ComponentName.unflattenFromString(curInteractor); 362 } 363 364 void setCurInteractor(ComponentName comp, int userHandle) { 365 Settings.Secure.putStringForUser(mContext.getContentResolver(), 366 Settings.Secure.VOICE_INTERACTION_SERVICE, 367 comp != null ? comp.flattenToShortString() : "", userHandle); 368 if (DEBUG) Slog.d(TAG, "setCurInteractor comp=" + comp 369 + " user=" + userHandle); 370 } 371 372 ComponentName findAvailRecognizer(String prefPackage, int userHandle) { 373 List<ResolveInfo> available = 374 mContext.getPackageManager().queryIntentServicesAsUser( 375 new Intent(RecognitionService.SERVICE_INTERFACE), 0, userHandle); 376 int numAvailable = available.size(); 377 378 if (numAvailable == 0) { 379 Slog.w(TAG, "no available voice recognition services found for user " + userHandle); 380 return null; 381 } else { 382 if (prefPackage != null) { 383 for (int i=0; i<numAvailable; i++) { 384 ServiceInfo serviceInfo = available.get(i).serviceInfo; 385 if (prefPackage.equals(serviceInfo.packageName)) { 386 return new ComponentName(serviceInfo.packageName, serviceInfo.name); 387 } 388 } 389 } 390 if (numAvailable > 1) { 391 Slog.w(TAG, "more than one voice recognition service found, picking first"); 392 } 393 394 ServiceInfo serviceInfo = available.get(0).serviceInfo; 395 return new ComponentName(serviceInfo.packageName, serviceInfo.name); 396 } 397 } 398 399 ComponentName getCurRecognizer(int userHandle) { 400 String curRecognizer = Settings.Secure.getStringForUser( 401 mContext.getContentResolver(), 402 Settings.Secure.VOICE_RECOGNITION_SERVICE, userHandle); 403 if (TextUtils.isEmpty(curRecognizer)) { 404 return null; 405 } 406 if (DEBUG) Slog.d(TAG, "getCurRecognizer curRecognizer=" + curRecognizer 407 + " user=" + userHandle); 408 return ComponentName.unflattenFromString(curRecognizer); 409 } 410 411 void setCurRecognizer(ComponentName comp, int userHandle) { 412 Settings.Secure.putStringForUser(mContext.getContentResolver(), 413 Settings.Secure.VOICE_RECOGNITION_SERVICE, 414 comp != null ? comp.flattenToShortString() : "", userHandle); 415 if (DEBUG) Slog.d(TAG, "setCurRecognizer comp=" + comp 416 + " user=" + userHandle); 417 } 418 419 @Override 420 public void showSession(IVoiceInteractionService service, Bundle args, int flags) { 421 synchronized (this) { 422 if (mImpl == null || mImpl.mService == null 423 || service.asBinder() != mImpl.mService.asBinder()) { 424 throw new SecurityException( 425 "Caller is not the current voice interaction service"); 426 } 427 final long caller = Binder.clearCallingIdentity(); 428 try { 429 mImpl.showSessionLocked(args, flags, null /* showCallback */); 430 } finally { 431 Binder.restoreCallingIdentity(caller); 432 } 433 } 434 } 435 436 @Override 437 public boolean deliverNewSession(IBinder token, IVoiceInteractionSession session, 438 IVoiceInteractor interactor) { 439 synchronized (this) { 440 if (mImpl == null) { 441 throw new SecurityException( 442 "deliverNewSession without running voice interaction service"); 443 } 444 final int callingPid = Binder.getCallingPid(); 445 final int callingUid = Binder.getCallingUid(); 446 final long caller = Binder.clearCallingIdentity(); 447 try { 448 return mImpl.deliverNewSessionLocked(callingPid, callingUid, token, session, 449 interactor); 450 } finally { 451 Binder.restoreCallingIdentity(caller); 452 } 453 } 454 } 455 456 @Override 457 public boolean showSessionFromSession(IBinder token, Bundle sessionArgs, int flags) { 458 synchronized (this) { 459 if (mImpl == null) { 460 Slog.w(TAG, "showSessionFromSession without running voice interaction service"); 461 return false; 462 } 463 final long caller = Binder.clearCallingIdentity(); 464 try { 465 return mImpl.showSessionLocked(sessionArgs, flags, null /* showCallback */); 466 } finally { 467 Binder.restoreCallingIdentity(caller); 468 } 469 } 470 } 471 472 @Override 473 public boolean hideSessionFromSession(IBinder token) { 474 synchronized (this) { 475 if (mImpl == null) { 476 Slog.w(TAG, "hideSessionFromSession without running voice interaction service"); 477 return false; 478 } 479 final long caller = Binder.clearCallingIdentity(); 480 try { 481 return mImpl.hideSessionLocked(); 482 } finally { 483 Binder.restoreCallingIdentity(caller); 484 } 485 } 486 } 487 488 @Override 489 public int startVoiceActivity(IBinder token, Intent intent, String resolvedType) { 490 synchronized (this) { 491 if (mImpl == null) { 492 Slog.w(TAG, "startVoiceActivity without running voice interaction service"); 493 return ActivityManager.START_CANCELED; 494 } 495 final int callingPid = Binder.getCallingPid(); 496 final int callingUid = Binder.getCallingUid(); 497 final long caller = Binder.clearCallingIdentity(); 498 try { 499 return mImpl.startVoiceActivityLocked(callingPid, callingUid, token, 500 intent, resolvedType); 501 } finally { 502 Binder.restoreCallingIdentity(caller); 503 } 504 } 505 } 506 507 @Override 508 public void setKeepAwake(IBinder token, boolean keepAwake) { 509 synchronized (this) { 510 if (mImpl == null) { 511 Slog.w(TAG, "setKeepAwake without running voice interaction service"); 512 return; 513 } 514 final int callingPid = Binder.getCallingPid(); 515 final int callingUid = Binder.getCallingUid(); 516 final long caller = Binder.clearCallingIdentity(); 517 try { 518 mImpl.setKeepAwakeLocked(callingPid, callingUid, token, keepAwake); 519 } finally { 520 Binder.restoreCallingIdentity(caller); 521 } 522 } 523 } 524 525 @Override 526 public void finish(IBinder token) { 527 synchronized (this) { 528 if (mImpl == null) { 529 Slog.w(TAG, "finish without running voice interaction service"); 530 return; 531 } 532 final long caller = Binder.clearCallingIdentity(); 533 try { 534 mImpl.finishLocked(token); 535 } finally { 536 Binder.restoreCallingIdentity(caller); 537 } 538 } 539 } 540 541 //----------------- Model management APIs --------------------------------// 542 543 @Override 544 public KeyphraseSoundModel getKeyphraseSoundModel(int keyphraseId, String bcp47Locale) { 545 enforceCallingPermission(Manifest.permission.MANAGE_VOICE_KEYPHRASES); 546 547 if (bcp47Locale == null) { 548 throw new IllegalArgumentException("Illegal argument(s) in getKeyphraseSoundModel"); 549 } 550 551 final int callingUid = UserHandle.getCallingUserId(); 552 final long caller = Binder.clearCallingIdentity(); 553 try { 554 return mDbHelper.getKeyphraseSoundModel(keyphraseId, callingUid, bcp47Locale); 555 } finally { 556 Binder.restoreCallingIdentity(caller); 557 } 558 } 559 560 @Override 561 public int updateKeyphraseSoundModel(KeyphraseSoundModel model) { 562 enforceCallingPermission(Manifest.permission.MANAGE_VOICE_KEYPHRASES); 563 if (model == null) { 564 throw new IllegalArgumentException("Model must not be null"); 565 } 566 567 final long caller = Binder.clearCallingIdentity(); 568 try { 569 if (mDbHelper.updateKeyphraseSoundModel(model)) { 570 synchronized (this) { 571 // Notify the voice interaction service of a change in sound models. 572 if (mImpl != null && mImpl.mService != null) { 573 mImpl.notifySoundModelsChangedLocked(); 574 } 575 } 576 return SoundTriggerHelper.STATUS_OK; 577 } else { 578 return SoundTriggerHelper.STATUS_ERROR; 579 } 580 } finally { 581 Binder.restoreCallingIdentity(caller); 582 } 583 } 584 585 @Override 586 public int deleteKeyphraseSoundModel(int keyphraseId, String bcp47Locale) { 587 enforceCallingPermission(Manifest.permission.MANAGE_VOICE_KEYPHRASES); 588 589 if (bcp47Locale == null) { 590 throw new IllegalArgumentException( 591 "Illegal argument(s) in deleteKeyphraseSoundModel"); 592 } 593 594 final int callingUid = UserHandle.getCallingUserId(); 595 final long caller = Binder.clearCallingIdentity(); 596 boolean deleted = false; 597 try { 598 deleted = mDbHelper.deleteKeyphraseSoundModel(keyphraseId, callingUid, bcp47Locale); 599 return deleted ? SoundTriggerHelper.STATUS_OK : SoundTriggerHelper.STATUS_ERROR; 600 } finally { 601 if (deleted) { 602 synchronized (this) { 603 // Notify the voice interaction service of a change in sound models. 604 if (mImpl != null && mImpl.mService != null) { 605 mImpl.notifySoundModelsChangedLocked(); 606 } 607 } 608 } 609 Binder.restoreCallingIdentity(caller); 610 } 611 } 612 613 //----------------- SoundTrigger APIs --------------------------------// 614 @Override 615 public boolean isEnrolledForKeyphrase(IVoiceInteractionService service, int keyphraseId, 616 String bcp47Locale) { 617 synchronized (this) { 618 if (mImpl == null || mImpl.mService == null 619 || service.asBinder() != mImpl.mService.asBinder()) { 620 throw new SecurityException( 621 "Caller is not the current voice interaction service"); 622 } 623 } 624 625 if (bcp47Locale == null) { 626 throw new IllegalArgumentException("Illegal argument(s) in isEnrolledForKeyphrase"); 627 } 628 629 final int callingUid = UserHandle.getCallingUserId(); 630 final long caller = Binder.clearCallingIdentity(); 631 try { 632 KeyphraseSoundModel model = 633 mDbHelper.getKeyphraseSoundModel(keyphraseId, callingUid, bcp47Locale); 634 return model != null; 635 } finally { 636 Binder.restoreCallingIdentity(caller); 637 } 638 } 639 640 @Override 641 public ModuleProperties getDspModuleProperties(IVoiceInteractionService service) { 642 // Allow the call if this is the current voice interaction service. 643 synchronized (this) { 644 if (mImpl == null || mImpl.mService == null 645 || service == null || service.asBinder() != mImpl.mService.asBinder()) { 646 throw new SecurityException( 647 "Caller is not the current voice interaction service"); 648 } 649 650 final long caller = Binder.clearCallingIdentity(); 651 try { 652 return mSoundTriggerHelper.moduleProperties; 653 } finally { 654 Binder.restoreCallingIdentity(caller); 655 } 656 } 657 } 658 659 @Override 660 public int startRecognition(IVoiceInteractionService service, int keyphraseId, 661 String bcp47Locale, IRecognitionStatusCallback callback, 662 RecognitionConfig recognitionConfig) { 663 // Allow the call if this is the current voice interaction service. 664 synchronized (this) { 665 if (mImpl == null || mImpl.mService == null 666 || service == null || service.asBinder() != mImpl.mService.asBinder()) { 667 throw new SecurityException( 668 "Caller is not the current voice interaction service"); 669 } 670 671 if (callback == null || recognitionConfig == null || bcp47Locale == null) { 672 throw new IllegalArgumentException("Illegal argument(s) in startRecognition"); 673 } 674 } 675 676 int callingUid = UserHandle.getCallingUserId(); 677 final long caller = Binder.clearCallingIdentity(); 678 try { 679 KeyphraseSoundModel soundModel = 680 mDbHelper.getKeyphraseSoundModel(keyphraseId, callingUid, bcp47Locale); 681 if (soundModel == null 682 || soundModel.uuid == null 683 || soundModel.keyphrases == null) { 684 Slog.w(TAG, "No matching sound model found in startRecognition"); 685 return SoundTriggerHelper.STATUS_ERROR; 686 } else { 687 return mSoundTriggerHelper.startRecognition( 688 keyphraseId, soundModel, callback, recognitionConfig); 689 } 690 } finally { 691 Binder.restoreCallingIdentity(caller); 692 } 693 } 694 695 @Override 696 public int stopRecognition(IVoiceInteractionService service, int keyphraseId, 697 IRecognitionStatusCallback callback) { 698 // Allow the call if this is the current voice interaction service. 699 synchronized (this) { 700 if (mImpl == null || mImpl.mService == null 701 || service == null || service.asBinder() != mImpl.mService.asBinder()) { 702 throw new SecurityException( 703 "Caller is not the current voice interaction service"); 704 } 705 } 706 707 final long caller = Binder.clearCallingIdentity(); 708 try { 709 return mSoundTriggerHelper.stopRecognition(keyphraseId, callback); 710 } finally { 711 Binder.restoreCallingIdentity(caller); 712 } 713 } 714 715 @Override 716 public ComponentName getActiveServiceComponentName() { 717 enforceCallingPermission(Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE); 718 synchronized (this) { 719 return mImpl != null ? mImpl.mComponent : null; 720 } 721 } 722 723 @Override 724 public void showSessionForActiveService(IVoiceInteractionSessionShowCallback showCallback) { 725 enforceCallingPermission(Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE); 726 synchronized (this) { 727 if (mImpl == null) { 728 Slog.w(TAG, "showSessionForActiveService without running voice interaction" 729 + "service"); 730 return; 731 } 732 final long caller = Binder.clearCallingIdentity(); 733 try { 734 mImpl.showSessionLocked(new Bundle() /* sessionArgs */, 735 VoiceInteractionSession.SHOW_SOURCE_ASSIST_GESTURE 736 | VoiceInteractionSession.SHOW_WITH_ASSIST 737 | VoiceInteractionSession.SHOW_WITH_SCREENSHOT, 738 showCallback); 739 } finally { 740 Binder.restoreCallingIdentity(caller); 741 } 742 } 743 } 744 745 @Override 746 public void hideCurrentSession() throws RemoteException { 747 enforceCallingPermission(Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE); 748 synchronized (this) { 749 if (mImpl == null) { 750 return; 751 } 752 final long caller = Binder.clearCallingIdentity(); 753 try { 754 if (mImpl.mActiveSession != null && mImpl.mActiveSession.mSession != null) { 755 try { 756 mImpl.mActiveSession.mSession.closeSystemDialogs(); 757 } catch (RemoteException e) { 758 Log.w(TAG, "Failed to call closeSystemDialogs", e); 759 } 760 } 761 } finally { 762 Binder.restoreCallingIdentity(caller); 763 } 764 } 765 } 766 767 @Override 768 public void launchVoiceAssistFromKeyguard() { 769 enforceCallingPermission(Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE); 770 synchronized (this) { 771 if (mImpl == null) { 772 Slog.w(TAG, "launchVoiceAssistFromKeyguard without running voice interaction" 773 + "service"); 774 return; 775 } 776 final long caller = Binder.clearCallingIdentity(); 777 try { 778 mImpl.launchVoiceAssistFromKeyguard(); 779 } finally { 780 Binder.restoreCallingIdentity(caller); 781 } 782 } 783 } 784 785 @Override 786 public boolean isSessionRunning() { 787 enforceCallingPermission(Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE); 788 synchronized (this) { 789 return mImpl != null && mImpl.mActiveSession != null; 790 } 791 } 792 793 @Override 794 public boolean activeServiceSupportsAssist() { 795 enforceCallingPermission(Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE); 796 synchronized (this) { 797 return mImpl != null && mImpl.mInfo != null && mImpl.mInfo.getSupportsAssist(); 798 } 799 } 800 801 @Override 802 public boolean activeServiceSupportsLaunchFromKeyguard() throws RemoteException { 803 enforceCallingPermission(Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE); 804 synchronized (this) { 805 return mImpl != null && mImpl.mInfo != null 806 && mImpl.mInfo.getSupportsLaunchFromKeyguard(); 807 } 808 } 809 810 @Override 811 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 812 if (mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP) 813 != PackageManager.PERMISSION_GRANTED) { 814 pw.println("Permission Denial: can't dump PowerManager from from pid=" 815 + Binder.getCallingPid() 816 + ", uid=" + Binder.getCallingUid()); 817 return; 818 } 819 synchronized (this) { 820 pw.println("VOICE INTERACTION MANAGER (dumpsys voiceinteraction)\n"); 821 pw.println(" mEnableService: " + mEnableService); 822 if (mImpl == null) { 823 pw.println(" (No active implementation)"); 824 return; 825 } 826 mImpl.dumpLocked(fd, pw, args); 827 } 828 mSoundTriggerHelper.dump(fd, pw, args); 829 } 830 831 private void enforceCallingPermission(String permission) { 832 if (mContext.checkCallingPermission(permission) != PackageManager.PERMISSION_GRANTED) { 833 throw new SecurityException("Caller does not hold the permission " + permission); 834 } 835 } 836 837 class SettingsObserver extends ContentObserver { 838 SettingsObserver(Handler handler) { 839 super(handler); 840 ContentResolver resolver = mContext.getContentResolver(); 841 resolver.registerContentObserver(Settings.Secure.getUriFor( 842 Settings.Secure.VOICE_INTERACTION_SERVICE), false, this); 843 } 844 845 @Override public void onChange(boolean selfChange) { 846 synchronized (VoiceInteractionManagerServiceStub.this) { 847 switchImplementationIfNeededLocked(false); 848 } 849 } 850 } 851 852 PackageMonitor mPackageMonitor = new PackageMonitor() { 853 @Override 854 public boolean onHandleForceStop(Intent intent, String[] packages, int uid, boolean doit) { 855 return super.onHandleForceStop(intent, packages, uid, doit); 856 } 857 858 @Override 859 public void onHandleUserStop(Intent intent, int userHandle) { 860 } 861 862 @Override 863 public void onSomePackagesChanged() { 864 int userHandle = getChangingUserId(); 865 if (DEBUG) Slog.d(TAG, "onSomePackagesChanged user=" + userHandle); 866 867 ComponentName curInteractor = getCurInteractor(userHandle); 868 ComponentName curRecognizer = getCurRecognizer(userHandle); 869 if (curRecognizer == null) { 870 // Could a new recognizer appear when we don't have one pre-installed? 871 if (anyPackagesAppearing()) { 872 curRecognizer = findAvailRecognizer(null, userHandle); 873 if (curRecognizer != null) { 874 setCurRecognizer(curRecognizer, userHandle); 875 } 876 } 877 return; 878 } 879 880 if (curInteractor != null) { 881 int change = isPackageDisappearing(curInteractor.getPackageName()); 882 if (change == PACKAGE_PERMANENT_CHANGE) { 883 // The currently set interactor is permanently gone; fall back to 884 // the default config. 885 setCurInteractor(null, userHandle); 886 setCurRecognizer(null, userHandle); 887 initForUser(userHandle); 888 return; 889 } 890 891 change = isPackageAppearing(curInteractor.getPackageName()); 892 if (change != PACKAGE_UNCHANGED) { 893 // If current interactor is now appearing, for any reason, then 894 // restart our connection with it. 895 if (mImpl != null && curInteractor.getPackageName().equals( 896 mImpl.mComponent.getPackageName())) { 897 switchImplementationIfNeededLocked(true); 898 } 899 } 900 return; 901 } 902 903 // There is no interactor, so just deal with a simple recognizer. 904 int change = isPackageDisappearing(curRecognizer.getPackageName()); 905 if (change == PACKAGE_PERMANENT_CHANGE 906 || change == PACKAGE_TEMPORARY_CHANGE) { 907 setCurRecognizer(findAvailRecognizer(null, userHandle), userHandle); 908 909 } else if (isPackageModified(curRecognizer.getPackageName())) { 910 setCurRecognizer(findAvailRecognizer(curRecognizer.getPackageName(), 911 userHandle), userHandle); 912 } 913 } 914 }; 915 } 916} 917