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