209 lines
8.8 KiB
C++
209 lines
8.8 KiB
C++
/*
|
|
* Copyright (C) 2015 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 "audioserver"
|
|
//#define LOG_NDEBUG 0
|
|
|
|
#include <algorithm>
|
|
|
|
#include <fcntl.h>
|
|
#include <sys/prctl.h>
|
|
#include <sys/wait.h>
|
|
#include <cutils/properties.h>
|
|
|
|
#include <android/media/audio/common/AudioMMapPolicy.h>
|
|
#include <android/media/audio/common/AudioMMapPolicyInfo.h>
|
|
#include <android/media/audio/common/AudioMMapPolicyType.h>
|
|
#include <android/media/IAudioFlingerService.h>
|
|
#include <binder/IPCThreadState.h>
|
|
#include <binder/ProcessState.h>
|
|
#include <binder/IServiceManager.h>
|
|
#include <hidl/HidlTransportSupport.h>
|
|
#include <mediautils/LimitProcessMemory.h>
|
|
#include <utils/Log.h>
|
|
|
|
// from include_dirs
|
|
#include "AudioFlinger.h"
|
|
#include "AudioPolicyService.h"
|
|
#include "AAudioService.h"
|
|
#include "utility/AAudioUtilities.h"
|
|
#include "MediaLogService.h"
|
|
|
|
using namespace android;
|
|
|
|
using android::media::audio::common::AudioMMapPolicy;
|
|
using android::media::audio::common::AudioMMapPolicyInfo;
|
|
using android::media::audio::common::AudioMMapPolicyType;
|
|
|
|
int main(int argc __unused, char **argv)
|
|
{
|
|
ALOGD("%s: starting", __func__);
|
|
const auto startTime = std::chrono::steady_clock::now();
|
|
// TODO: update with refined parameters
|
|
limitProcessMemory(
|
|
"audio.maxmem", /* "ro.audio.maxmem", property that defines limit */
|
|
(size_t)512 * (1 << 20), /* SIZE_MAX, upper limit in bytes */
|
|
20 /* upper limit as percentage of physical RAM */);
|
|
|
|
signal(SIGPIPE, SIG_IGN);
|
|
|
|
#if 1
|
|
// FIXME See bug 165702394 and bug 168511485
|
|
const bool doLog = false;
|
|
#else
|
|
bool doLog = (bool) property_get_bool("ro.test_harness", 0);
|
|
#endif
|
|
|
|
pid_t childPid;
|
|
// FIXME The advantage of making the process containing media.log service the parent process of
|
|
// the process that contains the other audio services, is that it allows us to collect more
|
|
// detailed information such as signal numbers, stop and continue, resource usage, etc.
|
|
// But it is also more complex. Consider replacing this by independent processes, and using
|
|
// binder on death notification instead.
|
|
if (doLog && (childPid = fork()) != 0) {
|
|
// media.log service
|
|
//prctl(PR_SET_NAME, (unsigned long) "media.log", 0, 0, 0);
|
|
// unfortunately ps ignores PR_SET_NAME for the main thread, so use this ugly hack
|
|
strcpy(argv[0], "media.log");
|
|
sp<ProcessState> proc(ProcessState::self());
|
|
MediaLogService::instantiate();
|
|
ProcessState::self()->startThreadPool();
|
|
IPCThreadState::self()->joinThreadPool();
|
|
for (;;) {
|
|
siginfo_t info;
|
|
int ret = TEMP_FAILURE_RETRY(waitid(P_PID, childPid, &info,
|
|
WEXITED | WSTOPPED | WCONTINUED));
|
|
if (ret < 0) {
|
|
break;
|
|
}
|
|
char buffer[32];
|
|
const char *code;
|
|
switch (info.si_code) {
|
|
case CLD_EXITED:
|
|
code = "CLD_EXITED";
|
|
break;
|
|
case CLD_KILLED:
|
|
code = "CLD_KILLED";
|
|
break;
|
|
case CLD_DUMPED:
|
|
code = "CLD_DUMPED";
|
|
break;
|
|
case CLD_STOPPED:
|
|
code = "CLD_STOPPED";
|
|
break;
|
|
case CLD_TRAPPED:
|
|
code = "CLD_TRAPPED";
|
|
break;
|
|
case CLD_CONTINUED:
|
|
code = "CLD_CONTINUED";
|
|
break;
|
|
default:
|
|
snprintf(buffer, sizeof(buffer), "unknown (%d)", info.si_code);
|
|
code = buffer;
|
|
break;
|
|
}
|
|
struct rusage usage;
|
|
getrusage(RUSAGE_CHILDREN, &usage);
|
|
ALOG(LOG_ERROR, "media.log", "pid %d status %d code %s user %ld.%03lds sys %ld.%03lds",
|
|
info.si_pid, info.si_status, code,
|
|
usage.ru_utime.tv_sec, usage.ru_utime.tv_usec / 1000,
|
|
usage.ru_stime.tv_sec, usage.ru_stime.tv_usec / 1000);
|
|
sp<IServiceManager> sm = defaultServiceManager();
|
|
sp<IBinder> binder = sm->getService(String16("media.log"));
|
|
if (binder != 0) {
|
|
Vector<String16> args;
|
|
binder->dump(-1, args);
|
|
}
|
|
switch (info.si_code) {
|
|
case CLD_EXITED:
|
|
case CLD_KILLED:
|
|
case CLD_DUMPED: {
|
|
ALOG(LOG_INFO, "media.log", "exiting");
|
|
_exit(0);
|
|
// not reached
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
// all other services
|
|
if (doLog) {
|
|
prctl(PR_SET_PDEATHSIG, SIGKILL); // if parent media.log dies before me, kill me also
|
|
setpgid(0, 0); // but if I die first, don't kill my parent
|
|
}
|
|
android::hardware::configureRpcThreadpool(4, false /*callerWillJoin*/);
|
|
|
|
// Ensure threads for possible callbacks. Note that get_audio_flinger() does
|
|
// this automatically when called from AudioPolicy, but we do this anyways here.
|
|
ProcessState::self()->startThreadPool();
|
|
|
|
// Instantiating AudioFlinger (making it public, e.g. through ::initialize())
|
|
// and then instantiating AudioPolicy (and making it public)
|
|
// leads to situations where AudioFlinger is accessed remotely before
|
|
// AudioPolicy is initialized. Not only might this
|
|
// cause inaccurate results, but if AudioPolicy has slow audio HAL
|
|
// initialization, it can cause a TimeCheck abort to occur on an AudioFlinger
|
|
// call which tries to access AudioPolicy.
|
|
//
|
|
// We create AudioFlinger and AudioPolicy locally then make it public to ServiceManager.
|
|
// This requires both AudioFlinger and AudioPolicy to be in-proc.
|
|
//
|
|
const auto af = sp<AudioFlinger>::make();
|
|
const auto afAdapter = sp<AudioFlingerServerAdapter>::make(af);
|
|
ALOGD("%s: AudioFlinger created", __func__);
|
|
ALOGW_IF(AudioSystem::setLocalAudioFlinger(af) != OK,
|
|
"%s: AudioSystem already has an AudioFlinger instance!", __func__);
|
|
const auto aps = sp<AudioPolicyService>::make();
|
|
ALOGD("%s: AudioPolicy created", __func__);
|
|
|
|
// Add AudioFlinger and AudioPolicy to ServiceManager.
|
|
sp<IServiceManager> sm = defaultServiceManager();
|
|
sm->addService(String16(IAudioFlinger::DEFAULT_SERVICE_NAME), afAdapter,
|
|
false /* allowIsolated */, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT);
|
|
sm->addService(String16(AudioPolicyService::getServiceName()), aps,
|
|
false /* allowIsolated */, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT);
|
|
|
|
// AAudioService should only be used in OC-MR1 and later.
|
|
// And only enable the AAudioService if the system MMAP policy explicitly allows it.
|
|
// This prevents a client from misusing AAudioService when it is not supported.
|
|
// If we cannot get audio flinger here, there must be some serious problems. In that case,
|
|
// attempting to call audio flinger on a null pointer could make the process crash
|
|
// and attract attentions.
|
|
std::vector<AudioMMapPolicyInfo> policyInfos;
|
|
status_t status = af->getMmapPolicyInfos(
|
|
AudioMMapPolicyType::DEFAULT, &policyInfos);
|
|
// Initialize aaudio service when querying mmap policy succeeds and
|
|
// any of the policy supports MMAP.
|
|
if (status == NO_ERROR &&
|
|
std::any_of(policyInfos.begin(), policyInfos.end(), [](const auto& info) {
|
|
return info.mmapPolicy == AudioMMapPolicy::AUTO ||
|
|
info.mmapPolicy == AudioMMapPolicy::ALWAYS;
|
|
})) {
|
|
AAudioService::instantiate();
|
|
} else {
|
|
ALOGD("%s: Do not init aaudio service, status %d, policy info size %zu",
|
|
__func__, status, policyInfos.size());
|
|
}
|
|
const auto endTime = std::chrono::steady_clock::now();
|
|
using FloatMillis = std::chrono::duration<float, std::milli>;
|
|
const float timeTaken = std::chrono::duration_cast<FloatMillis>(
|
|
endTime - startTime).count();
|
|
ALOGI("%s: initialization done in %.3f ms, joining thread pool", __func__, timeTaken);
|
|
IPCThreadState::self()->joinThreadPool();
|
|
}
|
|
}
|