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