From 77df5adde0fcd8a293558655d7b2a76ca4e124d1 Mon Sep 17 00:00:00 2001 From: Michael Bestas Date: Wed, 27 Dec 2017 23:57:24 +0200 Subject: [PATCH] Revert "cmsdk: Broker out CMAudioService" This reverts commit 705716fc60c62d9036e8c8e804c4110231c804d9 and partially reverts commit 8f33604af61ed34b846d5c8c272034c46265e6d8 adapted for LineageOS rebrand. Change-Id: Ia50f8430113dd54050697bcca9c6f5c337d61363 --- lineage/jni/Android.mk | 43 +++++ lineage/jni/src/onload.cpp | 45 +++++ ..._platform_internal_LineageAudioService.cpp | 170 ++++++++++++++++++ .../internal/LineageAudioService.java | 161 +++++++++++++++++ .../internal/LineageAudioServiceBroker.java | 130 -------------- .../platform/internal/NativeHelper.java | 44 +++++ lineage/res/AndroidManifest.xml | 10 +- lineage/res/res/values/config.xml | 2 +- lineage/res/res/values/strings.xml | 5 - 9 files changed, 465 insertions(+), 145 deletions(-) create mode 100644 lineage/jni/Android.mk create mode 100644 lineage/jni/src/onload.cpp create mode 100644 lineage/jni/src/org_lineageos_platform_internal_LineageAudioService.cpp create mode 100644 lineage/lib/main/java/org/lineageos/platform/internal/LineageAudioService.java delete mode 100644 lineage/lib/main/java/org/lineageos/platform/internal/LineageAudioServiceBroker.java create mode 100644 lineage/lib/main/java/org/lineageos/platform/internal/NativeHelper.java diff --git a/lineage/jni/Android.mk b/lineage/jni/Android.mk new file mode 100644 index 00000000..65821e2e --- /dev/null +++ b/lineage/jni/Android.mk @@ -0,0 +1,43 @@ +# Copyright (C) 2016 The CyanogenMod 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. + +LOCAL_PATH:= $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := \ + src/org_lineageos_platform_internal_LineageAudioService.cpp \ + src/onload.cpp + +LOCAL_C_INCLUDES := \ + $(JNI_H_INCLUDE) \ + $(TOP)/frameworks/base/core/jni \ + $(TOP)/frameworks/av/include \ + $(TOP)/hardware/libhardware/include + +LOCAL_SHARED_LIBRARIES := \ + libandroid_runtime \ + libaudioclient \ + libcutils \ + libhardware \ + liblog \ + libmedia \ + libutils + +LOCAL_MODULE := liblineage-sdk_platform_jni +LOCAL_MODULE_TAGS := optional +LOCAL_CFLAGS := -Wall -Werror -Wno-unused-parameter + +include $(BUILD_SHARED_LIBRARY) + diff --git a/lineage/jni/src/onload.cpp b/lineage/jni/src/onload.cpp new file mode 100644 index 00000000..e1c65f61 --- /dev/null +++ b/lineage/jni/src/onload.cpp @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2016 The CyanogenMod 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. + */ + +#include "JNIHelp.h" +#include "jni.h" +#include "utils/Log.h" +#include "utils/misc.h" + +namespace android { + +int register_org_lineageos_platform_internal_LineageAudioService(JNIEnv* env); + +}; + +using namespace android; + +extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */) +{ + JNIEnv* env = NULL; + jint result = -1; + + if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) { + ALOGE("GetEnv failed!"); + return result; + } + ALOG_ASSERT(env, "Could not retrieve the env!"); + + register_org_lineageos_platform_internal_LineageAudioService(env); + + return JNI_VERSION_1_4; +} + diff --git a/lineage/jni/src/org_lineageos_platform_internal_LineageAudioService.cpp b/lineage/jni/src/org_lineageos_platform_internal_LineageAudioService.cpp new file mode 100644 index 00000000..dfee0051 --- /dev/null +++ b/lineage/jni/src/org_lineageos_platform_internal_LineageAudioService.cpp @@ -0,0 +1,170 @@ +/* +** +** Copyright 2016, The CyanogenMod 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_NDEBUG 0 + +#define LOG_TAG "LineageAudioService-JNI" + +#include + +#include +#include +#include "core_jni_helpers.h" +#include "android_media_AudioErrors.h" + +#include +#include + +#include +#include + +// ---------------------------------------------------------------------------- + +namespace android { + +static const char* const kClassPathName = "org/lineageos/platform/internal/LineageAudioService"; + +static jclass gArrayListClass; +static struct { + jmethodID add; + jmethodID toArray; +} gArrayListMethods; + +static struct { + jmethodID postAudioSessionEventFromNative; +} gAudioSessionEventHandlerMethods; + +static jclass gAudioSessionInfoClass; +static jmethodID gAudioSessionInfoCstor; + +static jobject gThiz; + +static Mutex gCallbackLock; + +// ---------------------------------------------------------------------------- + +static void +org_lineageos_platform_internal_LineageAudioService_session_info_callback(int event, + sp& info, bool added) +{ + AutoMutex _l(gCallbackLock); + + JNIEnv *env = AndroidRuntime::getJNIEnv(); + if (env == NULL) { + return; + } + + jobject jSession = env->NewObject(gAudioSessionInfoClass, gAudioSessionInfoCstor, + info->mSessionId, info->mStream, info->mFlags, info->mChannelMask, info->mUid); + + env->CallVoidMethod(gThiz, + gAudioSessionEventHandlerMethods.postAudioSessionEventFromNative, + event, jSession, added); + + env->DeleteLocalRef(jSession); +} + +static void +org_lineageos_platform_internal_LineageAudioService_registerAudioSessionCallback( + JNIEnv *env, jobject thiz, jboolean enabled) +{ + if (gThiz == NULL) { + gThiz = env->NewGlobalRef(thiz); + } + + AudioSystem::setAudioSessionCallback( enabled ? + org_lineageos_platform_internal_LineageAudioService_session_info_callback : NULL); +} + +static jint +org_lineageos_platform_internal_LineageAudioService_listAudioSessions(JNIEnv *env, jobject thiz, + jint streams, jobject jSessions) +{ + ALOGV("listAudioSessions"); + + if (jSessions == NULL) { + ALOGE("listAudioSessions NULL arraylist"); + return (jint)AUDIO_JAVA_BAD_VALUE; + } + if (!env->IsInstanceOf(jSessions, gArrayListClass)) { + ALOGE("listAudioSessions not an arraylist"); + return (jint)AUDIO_JAVA_BAD_VALUE; + } + + status_t status; + Vector< sp> sessions; + + status = AudioSystem::listAudioSessions((audio_stream_type_t)streams, sessions); + if (status != NO_ERROR) { + ALOGE("AudioSystem::listAudioSessions error %d", status); + } else { + ALOGV("AudioSystem::listAudioSessions count=%zu", sessions.size()); + } + + jint jStatus = nativeToJavaStatus(status); + if (jStatus != AUDIO_JAVA_SUCCESS) { + goto exit; + } + + for (size_t i = 0; i < sessions.size(); i++) { + const sp& s = sessions.itemAt(i); + + jobject jSession = env->NewObject(gAudioSessionInfoClass, gAudioSessionInfoCstor, + s->mSessionId, s->mStream, s->mFlags, s->mChannelMask, s->mUid); + + if (jSession == NULL) { + jStatus = (jint)AUDIO_JAVA_ERROR; + goto exit; + } + + env->CallBooleanMethod(jSessions, gArrayListMethods.add, jSession); + env->DeleteLocalRef(jSession); + } + +exit: + return jStatus; +} + + +// ---------------------------------------------------------------------------- + +static JNINativeMethod gMethods[] = { + {"native_listAudioSessions", "(ILjava/util/ArrayList;)I", + (void *)org_lineageos_platform_internal_LineageAudioService_listAudioSessions}, + {"native_registerAudioSessionCallback", "(Z)V", + (void *)org_lineageos_platform_internal_LineageAudioService_registerAudioSessionCallback}, +}; + +int register_org_lineageos_platform_internal_LineageAudioService(JNIEnv *env) +{ + jclass arrayListClass = FindClassOrDie(env, "java/util/ArrayList"); + gArrayListClass = MakeGlobalRefOrDie(env, arrayListClass); + gArrayListMethods.add = GetMethodIDOrDie(env, arrayListClass, "add", "(Ljava/lang/Object;)Z"); + gArrayListMethods.toArray = GetMethodIDOrDie(env, arrayListClass, "toArray", "()[Ljava/lang/Object;"); + + jclass audioSessionInfoClass = FindClassOrDie(env, "lineageos/media/AudioSessionInfo"); + gAudioSessionInfoClass = MakeGlobalRefOrDie(env, audioSessionInfoClass); + gAudioSessionInfoCstor = GetMethodIDOrDie(env, audioSessionInfoClass, "", "(IIIII)V"); + + gAudioSessionEventHandlerMethods.postAudioSessionEventFromNative = + GetMethodIDOrDie(env, env->FindClass(kClassPathName), + "audioSessionCallbackFromNative", "(ILlineageos/media/AudioSessionInfo;Z)V"); + + return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods)); +} + +} /* namespace android */ diff --git a/lineage/lib/main/java/org/lineageos/platform/internal/LineageAudioService.java b/lineage/lib/main/java/org/lineageos/platform/internal/LineageAudioService.java new file mode 100644 index 00000000..ffd439ea --- /dev/null +++ b/lineage/lib/main/java/org/lineageos/platform/internal/LineageAudioService.java @@ -0,0 +1,161 @@ +/* + * Copyright (C) 2016 The CyanogenMod 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. + */ +package org.lineageos.platform.internal; + +import android.content.Context; +import android.content.Intent; +import android.os.Binder; +import android.os.IBinder; +import android.os.RemoteException; +import android.os.UserHandle; +import android.util.Log; + +import com.android.server.SystemService; + +import java.io.FileDescriptor; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.List; + +import lineageos.app.LineageContextConstants; +import lineageos.media.AudioSessionInfo; +import lineageos.media.LineageAudioManager; +import lineageos.media.ILineageAudioService; +import lineageos.platform.Manifest; + +public class LineageAudioService extends LineageSystemService { + + private static final String TAG = "LineageAudioService"; + private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); + + private final Context mContext; + + private static final int AUDIO_STATUS_OK = 0; + + //keep in sync with include/media/AudioPolicy.h + private final static int AUDIO_OUTPUT_SESSION_EFFECTS_UPDATE = 10; + + public LineageAudioService(Context context) { + super(context); + + mContext = context; + } + + @Override + public String getFeatureDeclaration() { + return LineageContextConstants.Features.AUDIO; + } + + @Override + public void onStart() { + if (!NativeHelper.isNativeLibraryAvailable()) { + Log.wtf(TAG, "Lineage Audio service started by system server by native library is" + + "unavailable. Service will be unavailable."); + return; + } + publishBinderService(LineageContextConstants.LINEAGE_AUDIO_SERVICE, mBinder); + } + + @Override + public void onBootPhase(int phase) { + if (phase == PHASE_BOOT_COMPLETED) { + if (NativeHelper.isNativeLibraryAvailable()) { + native_registerAudioSessionCallback(true); + } + } + } + + private final IBinder mBinder = new ILineageAudioService.Stub() { + + @Override + public List listAudioSessions(int streamType) throws RemoteException { + final ArrayList sessions = new ArrayList(); + if (!NativeHelper.isNativeLibraryAvailable()) { + // no sessions for u + return sessions; + } + + int status = native_listAudioSessions(streamType, sessions); + if (status != AUDIO_STATUS_OK) { + Log.e(TAG, "Error retrieving audio sessions! status=" + status); + } + + return sessions; + } + + @Override + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG); + + pw.println(); + pw.println("Lineage Audio Service State:"); + try { + List sessions = listAudioSessions(-1); + if (sessions.size() > 0) { + pw.println(" Audio sessions:"); + for (AudioSessionInfo info : sessions) { + pw.println(" " + info.toString()); + } + } else { + pw.println(" No active audio sessions"); + } + } catch (RemoteException e) { + // nothing + } + } + }; + + private void broadcastSessionChanged(boolean added, AudioSessionInfo sessionInfo) { + Intent i = new Intent(LineageAudioManager.ACTION_AUDIO_SESSIONS_CHANGED); + i.putExtra(LineageAudioManager.EXTRA_SESSION_INFO, sessionInfo); + i.putExtra(LineageAudioManager.EXTRA_SESSION_ADDED, added); + + sendBroadcastToAll(i, Manifest.permission.OBSERVE_AUDIO_SESSIONS); + } + + private void sendBroadcastToAll(Intent intent, String receiverPermission) { + intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); + + final long ident = Binder.clearCallingIdentity(); + try { + if (DEBUG) Log.d(TAG, "Sending broadcast: " + intent.toString()); + + mContext.sendBroadcastAsUser(intent, UserHandle.ALL, receiverPermission); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + + /* + * Handles events from JNI + */ + private synchronized void audioSessionCallbackFromNative(int event, + AudioSessionInfo sessionInfo, boolean added) { + + switch (event) { + case AUDIO_OUTPUT_SESSION_EFFECTS_UPDATE: + broadcastSessionChanged(added, sessionInfo); + break; + default: + Log.e(TAG, "Unknown event " + event); + } + } + + private native final void native_registerAudioSessionCallback(boolean enabled); + + private native final int native_listAudioSessions( + int stream, ArrayList sessions); +} diff --git a/lineage/lib/main/java/org/lineageos/platform/internal/LineageAudioServiceBroker.java b/lineage/lib/main/java/org/lineageos/platform/internal/LineageAudioServiceBroker.java deleted file mode 100644 index c16a5166..00000000 --- a/lineage/lib/main/java/org/lineageos/platform/internal/LineageAudioServiceBroker.java +++ /dev/null @@ -1,130 +0,0 @@ -/** - * Copyright (C) 2016 The CyanogenMod 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. - */ -package org.lineageos.platform.internal; - -import org.lineageos.platform.internal.common.BrokeredServiceConnection; - -import android.annotation.NonNull; -import android.annotation.SdkConstant; -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.os.IBinder; -import android.os.RemoteException; -import android.util.Log; -import android.util.Slog; - -import java.io.FileDescriptor; -import java.io.PrintWriter; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import lineageos.app.LineageContextConstants; -import lineageos.media.AudioSessionInfo; -import lineageos.media.ILineageAudioService; - -public class LineageAudioServiceBroker extends BrokerableLineageSystemService { - - private static final String TAG = "LineageAudioServiceBroker"; - private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); - - private final Context mContext; - - private static final ComponentName TARGET_IMPLEMENTATION_COMPONENT = - new ComponentName("org.lineageos.lineageaudio.service", - "org.lineageos.lineageaudio.service.LineageAudioService"); - - public LineageAudioServiceBroker(Context context) { - super(context); - mContext = context; - } - - @Override - public void onBootPhase(int phase) { - super.onBootPhase(phase); - if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) { - publishBinderService(LineageContextConstants.LINEAGE_AUDIO_SERVICE, new BinderService()); - } - } - - @Override - public void onStart() { - if (DEBUG) Slog.d(TAG, "service started"); - } - - @Override - protected ILineageAudioService getIBinderAsIInterface(@NonNull IBinder service) { - return ILineageAudioService.Stub.asInterface(service); - } - - @Override - protected ILineageAudioService getDefaultImplementation() { - return mServiceStubForFailure; - } - - @Override - protected ComponentName getServiceComponent() { - return TARGET_IMPLEMENTATION_COMPONENT; - } - - private void checkPermission() { - mContext.enforceCallingOrSelfPermission( - lineageos.platform.Manifest.permission.OBSERVE_AUDIO_SESSIONS, null); - } - - @Override - public String getFeatureDeclaration() { - return LineageContextConstants.Features.AUDIO; - } - - private final ILineageAudioService mServiceStubForFailure = new ILineageAudioService.Stub() { - @Override - public List listAudioSessions(int streamType) throws RemoteException { - checkPermission(); - return Collections.emptyList(); - } - }; - - private final class BinderService extends ILineageAudioService.Stub { - @Override - public List listAudioSessions(int streamType) throws RemoteException { - checkPermission(); - return getBrokeredService().listAudioSessions(streamType); - } - - @Override - public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG); - - pw.println(); - pw.println("LineageAudio Service State:"); - try { - List sessions = listAudioSessions(-1); - if (sessions.size() > 0) { - pw.println(" Audio sessions:"); - for (AudioSessionInfo info : sessions) { - pw.println(" " + info.toString()); - } - } else { - pw.println(" No active audio sessions"); - } - } catch (RemoteException e) { - // nothing - } - } - } -} diff --git a/lineage/lib/main/java/org/lineageos/platform/internal/NativeHelper.java b/lineage/lib/main/java/org/lineageos/platform/internal/NativeHelper.java new file mode 100644 index 00000000..611623b5 --- /dev/null +++ b/lineage/lib/main/java/org/lineageos/platform/internal/NativeHelper.java @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2016, The CyanogenMod 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. + */ +package org.lineageos.platform.internal; + +import android.util.Log; + +class NativeHelper { + + private static final String TAG = "Lineage-SDK-JNI"; + + private static Boolean sNativeLibraryLoaded; + + /** + * Loads the JNI backend if not already loaded. + * + * @return true if JNI platform library is loaded + */ + synchronized static boolean isNativeLibraryAvailable() { + if (sNativeLibraryLoaded == null) { + try { + System.loadLibrary("lineage-sdk_platform_jni"); + sNativeLibraryLoaded = true; + + } catch (Throwable t) { + sNativeLibraryLoaded = false; + Log.w(TAG, "Lineage-SDK native library unavailable"); + } + } + return sNativeLibraryLoaded; + } +} diff --git a/lineage/res/AndroidManifest.xml b/lineage/res/AndroidManifest.xml index b72f54a5..f430e6f7 100644 --- a/lineage/res/AndroidManifest.xml +++ b/lineage/res/AndroidManifest.xml @@ -24,8 +24,7 @@ - + @@ -182,13 +181,6 @@ android:description="@string/permdesc_observe_audio_sessions" android:protectionLevel="normal"/> - - - diff --git a/lineage/res/res/values/config.xml b/lineage/res/res/values/config.xml index 501d5f2a..33d220f5 100644 --- a/lineage/res/res/values/config.xml +++ b/lineage/res/res/values/config.xml @@ -125,7 +125,7 @@ org.lineageos.platform.internal.PerformanceManagerService org.lineageos.platform.internal.WeatherManagerServiceBroker org.lineageos.platform.internal.display.LiveDisplayService - org.lineageos.platform.internal.LineageAudioServiceBroker + org.lineageos.platform.internal.LineageAudioService diff --git a/lineage/res/res/values/strings.xml b/lineage/res/res/values/strings.xml index 944c8c5f..f93db964 100644 --- a/lineage/res/res/values/strings.xml +++ b/lineage/res/res/values/strings.xml @@ -187,11 +187,6 @@ observe audio session changes Allows an app to observe audio streams being created and destroyed. - - manage audio session changes - Allows an app to send audio stream updates. - - Privacy Guard