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