1/******************************************************************************
2 *
3 *  Copyright (C) 2012 Broadcom Corporation
4 *
5 *  Licensed under the Apache License, Version 2.0 (the "License");
6 *  you may not use this file except in compliance with the License.
7 *  You may obtain a copy of the License at:
8 *
9 *  http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *  Unless required by applicable law or agreed to in writing, software
12 *  distributed under the License is distributed on an "AS IS" BASIS,
13 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *  See the License for the specific language governing permissions and
15 *  limitations under the License.
16 *
17 ******************************************************************************/
18
19/*******************************************************************************
20 *
21 *  Filename:      bt_utils.cc
22 *
23 *  Description:   Miscellaneous helper functions
24 *
25 *
26 ******************************************************************************/
27
28#define LOG_TAG "bt_utils"
29
30#include "bt_utils.h"
31
32#include <errno.h>
33#include <pthread.h>
34#include <stdio.h>
35#include <stdlib.h>
36#include <sys/resource.h>
37#include <unistd.h>
38#include <mutex>
39
40#define A2DP_RT_PRIORITY 1
41#ifndef OS_GENERIC
42#include <cutils/sched_policy.h>
43#endif
44
45#include "bt_types.h"
46#include "btcore/include/module.h"
47#include "osi/include/compat.h"
48#include "osi/include/log.h"
49#include "osi/include/properties.h"
50
51/*******************************************************************************
52 *  Type definitions for callback functions
53 ******************************************************************************/
54static pthread_once_t g_DoSchedulingGroupOnce[TASK_HIGH_MAX];
55static bool g_DoSchedulingGroup[TASK_HIGH_MAX];
56static std::mutex gIdxLock;
57static int g_TaskIdx;
58static int g_TaskIDs[TASK_HIGH_MAX];
59#define INVALID_TASK_ID (-1)
60
61static future_t* init(void) {
62  int i;
63
64  for (i = 0; i < TASK_HIGH_MAX; i++) {
65    g_DoSchedulingGroupOnce[i] = PTHREAD_ONCE_INIT;
66    g_DoSchedulingGroup[i] = true;
67    g_TaskIDs[i] = INVALID_TASK_ID;
68  }
69
70  return NULL;
71}
72
73static future_t* clean_up(void) {
74  return NULL;
75}
76
77EXPORT_SYMBOL extern const module_t bt_utils_module = {.name = BT_UTILS_MODULE,
78                                                       .init = init,
79                                                       .start_up = NULL,
80                                                       .shut_down = NULL,
81                                                       .clean_up = clean_up,
82                                                       .dependencies = {NULL}};
83
84/*****************************************************************************
85 *
86 * Function        check_do_scheduling_group
87 *
88 * Description     check if it is ok to change schedule group
89 *
90 * Returns         void
91 *
92 ******************************************************************************/
93static void check_do_scheduling_group(void) {
94  char buf[PROPERTY_VALUE_MAX];
95  int len = osi_property_get("debug.sys.noschedgroups", buf, "");
96  if (len > 0) {
97    int temp;
98    if (sscanf(buf, "%d", &temp) == 1) {
99      g_DoSchedulingGroup[g_TaskIdx] = temp == 0;
100    }
101  }
102}
103
104/*****************************************************************************
105 *
106 * Function        raise_priority_a2dp
107 *
108 * Description     Raise task priority for A2DP streaming
109 *
110 * Returns         void
111 *
112 ******************************************************************************/
113void raise_priority_a2dp(tHIGH_PRIORITY_TASK high_task) {
114  int rc = 0;
115  int tid = gettid();
116
117  {
118    std::lock_guard<std::mutex> lock(gIdxLock);
119    g_TaskIdx = high_task;
120
121// TODO(armansito): Remove this conditional check once we find a solution
122// for system/core on non-Android platforms.
123#if defined(OS_GENERIC)
124    rc = -1;
125#else   // !defined(OS_GENERIC)
126    pthread_once(&g_DoSchedulingGroupOnce[g_TaskIdx],
127                 check_do_scheduling_group);
128    if (g_DoSchedulingGroup[g_TaskIdx]) {
129      // set_sched_policy does not support tid == 0
130      rc = set_sched_policy(tid, SP_AUDIO_SYS);
131    }
132#endif  // defined(OS_GENERIC)
133
134    g_TaskIDs[high_task] = tid;
135  }
136
137  if (rc) {
138    LOG_WARN(LOG_TAG, "failed to change sched policy, tid %d, err: %d", tid,
139             errno);
140  }
141
142  // make A2DP threads use RT scheduling policy since they are part of the
143  // audio pipeline
144  {
145    struct sched_param rt_params;
146    rt_params.sched_priority = A2DP_RT_PRIORITY;
147
148    const int rc = sched_setscheduler(tid, SCHED_FIFO, &rt_params);
149    if (rc != 0) {
150      LOG_ERROR(LOG_TAG,
151                "%s unable to set SCHED_FIFO priority %d for tid %d, error %s",
152                __func__, A2DP_RT_PRIORITY, tid, strerror(errno));
153    }
154  }
155}
156