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