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