前篇说了默认启动为异显状态,并且SystemUI 与键盘实现异显以及异显与同显的互相切换,
这篇说一下异显时第三方apk异声问题。
首先异声需要rockchip的补丁,合了补丁后在播放music之前,调用setAudioSessionId就可以决定输出的声卡。
所以看这篇文章需要先合rk补丁,由于补丁并不能区分第三分apk声音输入源,下面是我在framework做的区分源修改。
1.在activity启动时保存activity的包名及显示位置。
frameworks/base/core/java/android/app/ActivityThread.java 的 performResumeActivity函数中增加:
/*------add by hdb start----------------*/
//Slog.v(TAG, "hdb---performResumeActivity---");
final int displayId;
try {
displayId = ActivityTaskManager.getService().getActivityDisplayId(r.token);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
if(r.packageInfo != null){
String pName = r.packageInfo.getPackageName();
if(pName != null){
if(mActionManager == null){
if(getApplication() != null){
mActionManager = (ActionManager)getApplication().getSystemService(Context.ACTION_SERVICE);
}
}
if(mActionManager != null){
mActionManager.addPackageIdAndName(pName,displayId);
// Slog.i(TAG,"hdb---performResumeActivity---displayId:"+displayId +" pName:"+pName);
}
}
}
/*-------add by hdb end--------------*/
//备注一下,ActionManager 为自己添加的系统服务
2.在自己增加的系统服务中添加方法:
frameworks/base/core/java/android/app/ActionManager.java 文件中添加:
public void addPackageIdAndName(String name, int id){
try {
if(mService != null){
mService.addPackageIdAndName(name,id);
}
} catch (RemoteException ex) {
}
}
public int getIdFormPackageName(String name){
try {
if(mService != null){
return mService.getIdFormPackageName(name);
}
} catch (RemoteException ex) {
}
return 0;
}
public void setActiveToPackageName(String name, boolean active){
try {
if(mService != null){
mService.setActiveToPackageName(name,active);
}
} catch (RemoteException ex) {
}
}
public boolean getActiveFormPackageName(String name){
try {
if(mService != null){
return mService.getActiveFormPackageName(name);
}
} catch (RemoteException ex) {
}
return false;
}
frameworks/base/core/java/android/app/IActionManager.aidl 文件中添加:
void setActiveToPackageName(in String name, boolean active);
int getIdFormPackageName(in String name);^M
void addPackageIdAndName(in String name, int id);
boolean getActiveFormPackageName(in String name);
frameworks/base/services/java/com/android/server/ActionService.java 文件中添加
/*------------------------add by hdb start------------------------**/
private ArrayList<PackageIdAndName> mPackageIdAndNames = new ArrayList<PackageIdAndName>();
private Object mPackageIdLock = new Object();
public void addPackageIdAndName(String name, int id){
Slog.i(TAG,"hdb---addPackageIdAndName-0--name:"+name+" id:"+id);
synchronized (mPackageIdLock) {
if (mPackageIdAndNames.size() > 0) {
for (int i = 0; i < mPackageIdAndNames.size(); i++) {
PackageIdAndName packageIdAndName = mPackageIdAndNames.get(i);
if (packageIdAndName.getName().equalsIgnoreCase(name)) {
packageIdAndName.setId(id);
Slog.i(TAG,"hdb---addPackageIdAndName--11-id:"+id);
return;
}
}
}
Slog.i(TAG,"hdb---addPackageIdAndName--22-name:"+name+" id:"+id);
mPackageIdAndNames.add(new PackageIdAndName(name,id));
}
}
public void setActiveToPackageName(String name, boolean active){
Slog.i(TAG,"hdb---setActiveFormToPackageName-0--name:"+name+" active:"+active);
synchronized (mPackageIdLock) {
if (mPackageIdAndNames.size() > 0) {
for (int i = 0; i < mPackageIdAndNames.size(); i++) {
PackageIdAndName packageIdAndName = mPackageIdAndNames.get(i);
if (packageIdAndName.getName().equalsIgnoreCase(name)) {
packageIdAndName.setActive(active);
Slog.i(TAG,"hdb---setActiveFormToPackageName--11-active:"+active);
return;
}
}
}
}
}
public int getIdFormPackageName(String name){
if(mHandler.hasMessages(MSG_READ_MAX9191_0C)){
mHandler.removeMessages(MSG_READ_MAX9191_0C);
}
mHandler.sendEmptyMessageDelayed(MSG_READ_MAX9191_0C, MSG_READ_MAX9191_0C_DELAY);
Slog.i(TAG,"hdb---getIdFormPackageName-0--name:"+name+" size:"+mPackageIdAndNames.size());
synchronized (mPackageIdLock) {
if (mPackageIdAndNames.size() > 0) {
for (int i = 0; i < mPackageIdAndNames.size(); i++) {
PackageIdAndName packageIdAndName = mPackageIdAndNames.get(i);
// Slog.i(TAG,"hdb---getIdFormPackageName---getname:"+packageIdAndName.getName()+" name:"+name);
if (packageIdAndName.getName().equalsIgnoreCase(name)) {
Slog.i(TAG,"hdb---getIdFormPackageName-11--id:"+packageIdAndName.getId());
return packageIdAndName.getId();
}
}
}
Slog.i(TAG,"hdb---getIdFormPackageName--222--error----");
return 0;
}
}
public boolean getActiveFormPackageName(String name){
Slog.i(TAG,"hdb---getActiveFormPackageName-0--name:"+name+" size:"+mPackageIdAndNames.size());
synchronized (mPackageIdLock) {
if (mPackageIdAndNames.size() > 0) {
for (int i = 0; i < mPackageIdAndNames.size(); i++) {
PackageIdAndName packageIdAndName = mPackageIdAndNames.get(i);
//Slog.i(TAG,"hdb---getActiveFormPackageName---getname:"+packageIdAndName.getName()+" name:"+name);
if (packageIdAndName.getName().equalsIgnoreCase(name)) {
Slog.i(TAG,"hdb---getActiveFormPackageName-11--active:"+packageIdAndName.isActive());
return packageIdAndName.isActive();
}
}
}
Slog.i(TAG,"hdb---getActiveFormPackageName--222--error----");
return false;
}
}
private class PackageIdAndName{
private String name;
private int id;
private boolean active;
public PackageIdAndName(String name, int id) {
super();
this.name = name;
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public boolean isActive() {
return active;
}
public void setActive(boolean active) {
this.active = active;
}
}
/**-------------------------add by hdb end------------------------------------*/
3.audio播放最后都会跑frameworks/av/media/libaudioclient/AudioTrack.cpp
但是我保存的数据在自定义的服务中,所以这里需要跨进程通讯
1.新建文件
frameworks/native/libs/binder/IActionManager.cpp
--- /dev/null
+++ b/frameworks/native/libs/binder/IActionManager.cpp
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2005 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "IActionManager"
+
+#include <binder/IActionManager.h>
+
+#include <utils/Log.h>
+#include <binder/Parcel.h>
+#include <utils/String8.h>
+
+#include <private/binder/Static.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------
+
+class BpActionManager : public BpInterface<IActionManager>
+{
+public:
+ explicit BpActionManager(const sp<IBinder>& impl)
+ : BpInterface<IActionManager>(impl)
+ {
+ }
+
+ virtual void setActiveToPackageName(const String16& packageName, bool active)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IActionManager::getInterfaceDescriptor());
+ data.writeBool(active);
+ data.writeString16(packageName);
+ remote()->transact(SET_ACTIVE_TO_PACKAGENAME, data, &reply);
+
+ //int code = reply.readExceptionCode();
+ //ALOGD("hdb-----BpActionManager");
+ }
+
+ virtual int getIdFormPackageName(const String16& packageName)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IActionManager::getInterfaceDescriptor());
+ data.writeString16(packageName);
+ remote()->transact(GET_ID_FORM_PACKAGENAME, data, &reply);
+ // fail on exception
+ if (reply.readExceptionCode() != 0) return false;
+ return reply.readInt32();
+ }
+};
+
+IMPLEMENT_META_INTERFACE(ActionManager, "android.app.IActionManager");
+
+}; // namespace android
2.创建文件
frameworks/native/libs/binder/include/binder/IActionManager.h
--- /dev/null
+++ b/frameworks/native/libs/binder/include/binder/IActionManager.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2005 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//
+#ifndef ANDROID_IACTION_MANAGER_H
+#define ANDROID_IACTION_MANAGER_H
+
+#ifndef __ANDROID_VNDK__
+
+#include <binder/IInterface.h>
+#include <stdlib.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------
+
+class IActionManager : public IInterface
+{
+public:
+
+ DECLARE_META_INTERFACE(ActionManager)
+
+ virtual void setActiveToPackageName(const String16& packageName, bool active) = 0;
+ virtual int getIdFormPackageName(const String16& packageName) = 0;
+
+ enum {
+ SET_ACTIVE_TO_PACKAGENAME = IBinder::FIRST_CALL_TRANSACTION,
+ GET_ID_FORM_PACKAGENAME = IBinder::FIRST_CALL_TRANSACTION + 1,
+ };
+};
+
+// ----------------------------------------------------------------------
+
+}; // namespace android
+
+#else // __ANDROID_VNDK__
+#error "This header is not visible to vendors"
+#endif // __ANDROID_VNDK__
+
+#endif // ANDROID_IPERMISSION_CONTROLLER_H
+
3.android.bp中加入编译
index aedf6b0d18..af1ac33522 100644
--- a/frameworks/native/libs/binder/Android.bp
+++ b/frameworks/native/libs/binder/Android.bp
@@ -54,6 +54,7 @@ cc_library_shared {
"IMemory.cpp",
"IPCThreadState.cpp",
"IPermissionController.cpp",
+ "IActionManager.cpp",
"IProcessInfoService.cpp",
"IResultReceiver.cpp",
"IServiceManager.cpp",
@@ -88,6 +89,7 @@ cc_library_shared {
"IBatteryStats.cpp",
"IMediaResourceMonitor.cpp",
"IPermissionController.cpp",
+ "IActionManager.cpp",
"IProcessInfoService.cpp",
"IUidObserver.cpp",
"PermissionCache.cpp",
4.frameworks/av/media/libaudioclient/AudioTrack.cpp 文件跨进程调用
index 9a9f46d20f..bc881fc48b 100644
--- a/frameworks/av/media/libaudioclient/AudioTrack.cpp
+++ b/frameworks/av/media/libaudioclient/AudioTrack.cpp
@@ -37,6 +37,12 @@
#include <media/AudioSystem.h>
#include <media/MediaAnalyticsItem.h>
#include <media/TypeConverter.h>
+#include <binder/IServiceManager.h>// add by hdb
+#include <binder/PermissionController.h>
+#include <binder/IActionManager.h>
+
+
+
#define WAIT_PERIOD_MS 10
#define WAIT_STREAM_END_TIMEOUT_SEC 120
@@ -355,7 +361,6 @@ status_t AudioTrack::set(
uint32_t channelCount;
pid_t callingPid;
pid_t myPid;
-
// Note mPortId is not valid until the track is created, so omit mPortId in ALOG for set.
ALOGV("%s(): streamType %d, sampleRate %u, format %#x, channelMask %#x, frameCount %zu, "
"flags #%x, notificationFrames %d, sessionId %d, transferType %d, uid %d, pid %d",
@@ -1468,6 +1473,39 @@ status_t AudioTrack::createTrack_l()
}
uint32_t this_flags = (uint32_t)mFlags;
this_flags &= ~AUDIO_OUTPUT_DUAL_MASK;
+
+ /*------hdb-------------------------------------------------------------------------*/
+ uid_t callingUID = IPCThreadState::self()->getCallingUid();
+ ALOGD("hdb----createTrack_l---callingUID=%d",callingUID);
+ if(callingUID >= 10000){ //not system app
+ sp<IServiceManager> sm = defaultServiceManager();
+ sp<IBinder> binder = sm->getService(String16("permission"));
+ if (binder != 0) {
+ sp<IPermissionController> permCtrl = interface_cast<IPermissionController>(binder);
+ Vector<String16> packages;
+ permCtrl->getPackagesForUid(callingUID, packages);
+ if (!packages.isEmpty()) {
+ // String8 opPkg = (String8)packages[0].string();
+ // ALOGD("hdb----createTrack_l---opPkg:%s", opPkg.string());
+
+ sp<IBinder> binder1 = sm->getService(String16("action"));
+ if (binder1 != 0) {
+ ALOGD("hdb---binder1-createTrack_l--in-");
+ sp<IActionManager> actionM = interface_cast<IActionManager>(binder1);
+ int dislayId = actionM->getIdFormPackageName((String16)packages[0].string());
+ if(dislayId == 0){
+ mSessionId = (audio_session_t)121;
+ }else{
+ mSessionId = (audio_session_t)57;
+ }
+ }
+ }
+
+
+ }
+ }
+
+ /*-------hdb------------------------------------------------------------------------------*/
if(mSessionId == (audio_session_t)57){
ALOGD("set secondary sound flags");
this_flags |= AUDIO_OUTPUT_SECONDARY; // secondary sound