blob: 251f3146f8cc2cd79825a0ef5e6bf0d529d8d393 [file] [log] [blame]
Arunesh Mishraa772e5f2016-01-25 10:33:11 -08001/*
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.soundtrigger;
Arunesh Mishra3fff7f52016-02-09 12:15:19 -080018import static android.hardware.soundtrigger.SoundTrigger.STATUS_ERROR;
Arunesh Mishraa772e5f2016-01-25 10:33:11 -080019
20import android.content.Context;
21import android.content.pm.PackageManager;
22import android.Manifest;
23import android.hardware.soundtrigger.IRecognitionStatusCallback;
24import android.hardware.soundtrigger.SoundTrigger;
Arunesh Mishrac722ec412016-01-27 13:29:12 -080025import android.hardware.soundtrigger.SoundTrigger.GenericSoundModel;
Arunesh Mishraa772e5f2016-01-25 10:33:11 -080026import android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel;
Arunesh Mishra55a9b002016-02-01 14:06:37 -080027import android.hardware.soundtrigger.SoundTrigger.ModuleProperties;
Arunesh Mishraa772e5f2016-01-25 10:33:11 -080028import android.hardware.soundtrigger.SoundTrigger.RecognitionConfig;
Arunesh Mishraa772e5f2016-01-25 10:33:11 -080029import android.os.Parcel;
30import android.os.ParcelUuid;
31import android.os.RemoteException;
32import android.util.Slog;
33
34import com.android.server.SystemService;
35import com.android.internal.app.ISoundTriggerService;
36
37import java.io.FileDescriptor;
38import java.io.PrintWriter;
39import java.util.UUID;
40
41/**
42 * A single SystemService to manage all sound/voice-based sound models on the DSP.
43 * This services provides apis to manage sound trigger-based sound models via
44 * the ISoundTriggerService interface. This class also publishes a local interface encapsulating
45 * the functionality provided by {@link SoundTriggerHelper} for use by
46 * {@link VoiceInteractionManagerService}.
47 *
48 * @hide
49 */
50public class SoundTriggerService extends SystemService {
Arunesh Mishra3fff7f52016-02-09 12:15:19 -080051 private static final String TAG = "SoundTriggerService";
52 private static final boolean DEBUG = true;
Arunesh Mishraa772e5f2016-01-25 10:33:11 -080053
54 final Context mContext;
55 private final SoundTriggerServiceStub mServiceStub;
56 private final LocalSoundTriggerService mLocalSoundTriggerService;
57 private SoundTriggerDbHelper mDbHelper;
Arunesh Mishra3fff7f52016-02-09 12:15:19 -080058 private SoundTriggerHelper mSoundTriggerHelper;
Arunesh Mishraa772e5f2016-01-25 10:33:11 -080059
60 public SoundTriggerService(Context context) {
61 super(context);
62 mContext = context;
63 mServiceStub = new SoundTriggerServiceStub();
64 mLocalSoundTriggerService = new LocalSoundTriggerService(context);
65 }
66
67 @Override
68 public void onStart() {
69 publishBinderService(Context.SOUND_TRIGGER_SERVICE, mServiceStub);
70 publishLocalService(SoundTriggerInternal.class, mLocalSoundTriggerService);
71 }
72
73 @Override
74 public void onBootPhase(int phase) {
75 if (PHASE_SYSTEM_SERVICES_READY == phase) {
Arunesh Mishra3fff7f52016-02-09 12:15:19 -080076 initSoundTriggerHelper();
77 mLocalSoundTriggerService.setSoundTriggerHelper(mSoundTriggerHelper);
Arunesh Mishraa772e5f2016-01-25 10:33:11 -080078 } else if (PHASE_THIRD_PARTY_APPS_CAN_START == phase) {
79 mDbHelper = new SoundTriggerDbHelper(mContext);
80 }
81 }
82
83 @Override
84 public void onStartUser(int userHandle) {
85 }
86
87 @Override
88 public void onSwitchUser(int userHandle) {
89 }
90
Arunesh Mishra3fff7f52016-02-09 12:15:19 -080091 private synchronized void initSoundTriggerHelper() {
92 if (mSoundTriggerHelper == null) {
93 mSoundTriggerHelper = new SoundTriggerHelper(mContext);
94 }
95 }
96
97 private synchronized boolean isInitialized() {
98 if (mSoundTriggerHelper == null ) {
99 Slog.e(TAG, "SoundTriggerHelper not initialized.");
100 return false;
101 }
102 return true;
103 }
104
Arunesh Mishraa772e5f2016-01-25 10:33:11 -0800105 class SoundTriggerServiceStub extends ISoundTriggerService.Stub {
106 @Override
107 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
108 throws RemoteException {
109 try {
110 return super.onTransact(code, data, reply, flags);
111 } catch (RuntimeException e) {
112 // The activity manager only throws security exceptions, so let's
113 // log all others.
114 if (!(e instanceof SecurityException)) {
115 Slog.wtf(TAG, "SoundTriggerService Crash", e);
116 }
117 throw e;
118 }
119 }
120
121 @Override
Arunesh Mishra3fff7f52016-02-09 12:15:19 -0800122 public int startRecognition(ParcelUuid parcelUuid, IRecognitionStatusCallback callback,
123 RecognitionConfig config) {
Arunesh Mishraa772e5f2016-01-25 10:33:11 -0800124 enforceCallingPermission(Manifest.permission.MANAGE_SOUND_TRIGGER);
125 if (DEBUG) {
126 Slog.i(TAG, "startRecognition(): Uuid : " + parcelUuid);
127 }
Arunesh Mishra3fff7f52016-02-09 12:15:19 -0800128 if (!isInitialized()) return STATUS_ERROR;
129
130 GenericSoundModel model = getSoundModel(parcelUuid);
131 if (model == null) {
132 Slog.e(TAG, "Null model in database for id: " + parcelUuid);
133 return STATUS_ERROR;
134 }
135
136 return mSoundTriggerHelper.startGenericRecognition(parcelUuid.getUuid(), model,
137 callback, config);
Arunesh Mishraa772e5f2016-01-25 10:33:11 -0800138 }
139
140 @Override
Arunesh Mishra3fff7f52016-02-09 12:15:19 -0800141 public int stopRecognition(ParcelUuid parcelUuid, IRecognitionStatusCallback callback) {
Arunesh Mishraa772e5f2016-01-25 10:33:11 -0800142 enforceCallingPermission(Manifest.permission.MANAGE_SOUND_TRIGGER);
143 if (DEBUG) {
144 Slog.i(TAG, "stopRecognition(): Uuid : " + parcelUuid);
145 }
Arunesh Mishra3fff7f52016-02-09 12:15:19 -0800146 if (!isInitialized()) return STATUS_ERROR;
147 return mSoundTriggerHelper.stopGenericRecognition(parcelUuid.getUuid(), callback);
Arunesh Mishraa772e5f2016-01-25 10:33:11 -0800148 }
149
150 @Override
Arunesh Mishrac722ec412016-01-27 13:29:12 -0800151 public SoundTrigger.GenericSoundModel getSoundModel(ParcelUuid soundModelId) {
Arunesh Mishraa772e5f2016-01-25 10:33:11 -0800152 enforceCallingPermission(Manifest.permission.MANAGE_SOUND_TRIGGER);
153 if (DEBUG) {
154 Slog.i(TAG, "getSoundModel(): id = " + soundModelId);
155 }
Arunesh Mishra3fff7f52016-02-09 12:15:19 -0800156 SoundTrigger.GenericSoundModel model = mDbHelper.getGenericSoundModel(
157 soundModelId.getUuid());
Arunesh Mishraa772e5f2016-01-25 10:33:11 -0800158 return model;
159 }
160
161 @Override
Arunesh Mishrac722ec412016-01-27 13:29:12 -0800162 public void updateSoundModel(SoundTrigger.GenericSoundModel soundModel) {
Arunesh Mishraa772e5f2016-01-25 10:33:11 -0800163 enforceCallingPermission(Manifest.permission.MANAGE_SOUND_TRIGGER);
164 if (DEBUG) {
165 Slog.i(TAG, "updateSoundModel(): model = " + soundModel);
166 }
Arunesh Mishrac722ec412016-01-27 13:29:12 -0800167 mDbHelper.updateGenericSoundModel(soundModel);
Arunesh Mishraa772e5f2016-01-25 10:33:11 -0800168 }
169
170 @Override
171 public void deleteSoundModel(ParcelUuid soundModelId) {
172 enforceCallingPermission(Manifest.permission.MANAGE_SOUND_TRIGGER);
173 if (DEBUG) {
174 Slog.i(TAG, "deleteSoundModel(): id = " + soundModelId);
175 }
Arunesh Mishrac722ec412016-01-27 13:29:12 -0800176 mDbHelper.deleteGenericSoundModel(soundModelId.getUuid());
Arunesh Mishraa772e5f2016-01-25 10:33:11 -0800177 }
178 }
179
180 public final class LocalSoundTriggerService extends SoundTriggerInternal {
181 private final Context mContext;
182 private SoundTriggerHelper mSoundTriggerHelper;
183
184 LocalSoundTriggerService(Context context) {
185 mContext = context;
186 }
187
Arunesh Mishra3fff7f52016-02-09 12:15:19 -0800188 synchronized void setSoundTriggerHelper(SoundTriggerHelper helper) {
189 mSoundTriggerHelper = helper;
Arunesh Mishraa772e5f2016-01-25 10:33:11 -0800190 }
191
192 @Override
193 public int startRecognition(int keyphraseId, KeyphraseSoundModel soundModel,
194 IRecognitionStatusCallback listener, RecognitionConfig recognitionConfig) {
Arunesh Mishra3fff7f52016-02-09 12:15:19 -0800195 if (!isInitialized()) return STATUS_ERROR;
196 return mSoundTriggerHelper.startKeyphraseRecognition(keyphraseId, soundModel, listener,
Arunesh Mishraa772e5f2016-01-25 10:33:11 -0800197 recognitionConfig);
198 }
199
200 @Override
Arunesh Mishra3fff7f52016-02-09 12:15:19 -0800201 public synchronized int stopRecognition(int keyphraseId, IRecognitionStatusCallback listener) {
202 if (!isInitialized()) return STATUS_ERROR;
203 return mSoundTriggerHelper.stopKeyphraseRecognition(keyphraseId, listener);
Arunesh Mishraa772e5f2016-01-25 10:33:11 -0800204 }
205
206 @Override
207 public void stopAllRecognitions() {
Arunesh Mishra3fff7f52016-02-09 12:15:19 -0800208 if (!isInitialized()) return;
Arunesh Mishraa772e5f2016-01-25 10:33:11 -0800209 mSoundTriggerHelper.stopAllRecognitions();
210 }
211
212 @Override
Arunesh Mishra55a9b002016-02-01 14:06:37 -0800213 public ModuleProperties getModuleProperties() {
Arunesh Mishra3fff7f52016-02-09 12:15:19 -0800214 if (!isInitialized()) return null;
Arunesh Mishra55a9b002016-02-01 14:06:37 -0800215 return mSoundTriggerHelper.getModuleProperties();
216 }
217
218 @Override
Arunesh Mishraa772e5f2016-01-25 10:33:11 -0800219 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Arunesh Mishra3fff7f52016-02-09 12:15:19 -0800220 if (!isInitialized()) return;
Arunesh Mishraa772e5f2016-01-25 10:33:11 -0800221 mSoundTriggerHelper.dump(fd, pw, args);
222 }
Arunesh Mishra3fff7f52016-02-09 12:15:19 -0800223
224 private synchronized boolean isInitialized() {
225 if (mSoundTriggerHelper == null ) {
226 Slog.e(TAG, "SoundTriggerHelper not initialized.");
227 return false;
228 }
229 return true;
230 }
Arunesh Mishraa772e5f2016-01-25 10:33:11 -0800231 }
232
233 private void enforceCallingPermission(String permission) {
234 if (mContext.checkCallingOrSelfPermission(permission)
235 != PackageManager.PERMISSION_GRANTED) {
236 throw new SecurityException("Caller does not hold the permission " + permission);
237 }
238 }
239}