1/*
2 * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#include "entities/uid_entity.h"
17
18#ifdef SYS_MGR_CLIENT_ENABLE
19#include <bundle_constants.h>
20#include <bundle_mgr_interface.h>
21#include <ipc_skeleton.h>
22#include <system_ability_definition.h>
23#include <sys_mgr_client.h>
24#endif
25
26#include <ohos_account_kits_impl.h>
27#include "battery_stats_service.h"
28#include "stats_log.h"
29
30namespace OHOS {
31namespace PowerMgr {
32namespace {
33}
34
35UidEntity::UidEntity()
36{
37    consumptionType_ = BatteryStatsInfo::CONSUMPTION_TYPE_APP;
38}
39
40void UidEntity::UpdateUidMap(int32_t uid)
41{
42    std::lock_guard<std::mutex> lock(uidEntityMutex_);
43    if (uid > StatsUtils::INVALID_VALUE) {
44        auto iter = uidPowerMap_.find(uid);
45        if (iter != uidPowerMap_.end()) {
46            STATS_HILOGD(COMP_SVC, "Uid has already been added, ignore");
47        } else {
48            STATS_HILOGD(COMP_SVC, "Update %{public}d to uid power map", uid);
49            uidPowerMap_.insert(std::pair<int32_t, double>(uid, StatsUtils::DEFAULT_VALUE));
50        }
51    }
52}
53
54std::vector<int32_t> UidEntity::GetUids()
55{
56    std::lock_guard<std::mutex> lock(uidEntityMutex_);
57    std::vector<int32_t> uids;
58    std::transform(uidPowerMap_.begin(), uidPowerMap_.end(), std::back_inserter(uids), [](const auto& item) {
59        return item.first;
60    });
61    return uids;
62}
63
64double UidEntity::CalculateForConnectivity(int32_t uid)
65{
66    double power = StatsUtils::DEFAULT_VALUE;
67    auto bss = BatteryStatsService::GetInstance();
68    auto core = bss->GetBatteryStatsCore();
69    auto bluetoothEntity = core->GetEntity(BatteryStatsInfo::CONSUMPTION_TYPE_BLUETOOTH);
70
71    // Calculate bluetooth power consumption
72    bluetoothEntity->Calculate(uid);
73    power += bluetoothEntity->GetEntityPowerMah(uid);
74    STATS_HILOGD(COMP_SVC, "Connectivity power consumption: %{public}lfmAh for uid: %{public}d", power, uid);
75    return power;
76}
77
78double UidEntity::CalculateForCommon(int32_t uid)
79{
80    double power = StatsUtils::DEFAULT_VALUE;
81    auto bss = BatteryStatsService::GetInstance();
82    auto core = bss->GetBatteryStatsCore();
83    auto cameraEntity = core->GetEntity(BatteryStatsInfo::CONSUMPTION_TYPE_CAMERA);
84    auto flashlightEntity = core->GetEntity(BatteryStatsInfo::CONSUMPTION_TYPE_FLASHLIGHT);
85    auto audioEntity = core->GetEntity(BatteryStatsInfo::CONSUMPTION_TYPE_AUDIO);
86    auto sensorEntity = core->GetEntity(BatteryStatsInfo::CONSUMPTION_TYPE_SENSOR);
87    auto gnssEntity = core->GetEntity(BatteryStatsInfo::CONSUMPTION_TYPE_GNSS);
88    auto cpuEntity = core->GetEntity(BatteryStatsInfo::CONSUMPTION_TYPE_CPU);
89    auto wakelockEntity = core->GetEntity(BatteryStatsInfo::CONSUMPTION_TYPE_WAKELOCK);
90    auto alarmEntity = core->GetEntity(BatteryStatsInfo::CONSUMPTION_TYPE_ALARM);
91
92    // Calculate camera power consumption
93    cameraEntity->Calculate(uid);
94    power += cameraEntity->GetEntityPowerMah(uid);
95    // Calculate flashlight power consumption
96    flashlightEntity->Calculate(uid);
97    power += flashlightEntity->GetEntityPowerMah(uid);
98    // Calculate audio power consumption
99    audioEntity->Calculate(uid);
100    power += audioEntity->GetEntityPowerMah(uid);
101    // Calculate sensor power consumption
102    sensorEntity->Calculate(uid);
103    power += sensorEntity->GetEntityPowerMah(uid);
104    // Calculate gnss power consumption
105    gnssEntity->Calculate(uid);
106    power += gnssEntity->GetEntityPowerMah(uid);
107    // Calculate cpu power consumption
108    cpuEntity->Calculate(uid);
109    power += cpuEntity->GetEntityPowerMah(uid);
110    // Calculate cpu power consumption
111    wakelockEntity->Calculate(uid);
112    power += wakelockEntity->GetEntityPowerMah(uid);
113    // Calculate alarm power consumption
114    alarmEntity->Calculate(uid);
115    power += alarmEntity->GetEntityPowerMah(uid);
116
117    STATS_HILOGD(COMP_SVC, "Common power consumption: %{public}lfmAh for uid: %{public}d", power, uid);
118    return power;
119}
120
121void UidEntity::Calculate(int32_t uid)
122{
123    auto bss = BatteryStatsService::GetInstance();
124    std::lock_guard<std::mutex> lock(uidEntityMutex_);
125    auto core = bss->GetBatteryStatsCore();
126    auto userEntity = core->GetEntity(BatteryStatsInfo::CONSUMPTION_TYPE_USER);
127    for (auto& iter : uidPowerMap_) {
128        double power = StatsUtils::DEFAULT_VALUE;
129        power += CalculateForConnectivity(iter.first);
130        power += CalculateForCommon(iter.first);
131        iter.second = power;
132        totalPowerMah_ += power;
133        AddtoStatsList(iter.first, power);
134        int32_t uid = iter.first;
135        int32_t userId = AccountSA::OhosAccountKits::GetInstance().GetDeviceAccountIdByUID(uid);
136        if (userEntity != nullptr) {
137            userEntity->AggregateUserPowerMah(userId, power);
138        }
139    }
140}
141
142void UidEntity::AddtoStatsList(int32_t uid, double power)
143{
144    std::shared_ptr<BatteryStatsInfo> statsInfo = std::make_shared<BatteryStatsInfo>();
145    statsInfo->SetConsumptioType(BatteryStatsInfo::CONSUMPTION_TYPE_APP);
146    statsInfo->SetUid(uid);
147    statsInfo->SetPower(power);
148    statsInfoList_.push_back(statsInfo);
149}
150
151double UidEntity::GetEntityPowerMah(int32_t uidOrUserId)
152{
153    std::lock_guard<std::mutex> lock(uidEntityMutex_);
154    double power = StatsUtils::DEFAULT_VALUE;
155    auto iter = uidPowerMap_.find(uidOrUserId);
156    if (iter != uidPowerMap_.end()) {
157        power = iter->second;
158        STATS_HILOGD(COMP_SVC, "Get app uid power consumption: %{public}lfmAh for uid: %{public}d",
159            power, uidOrUserId);
160    } else {
161        STATS_HILOGD(COMP_SVC,
162            "No app uid power consumption related to uid: %{public}d was found, return 0", uidOrUserId);
163    }
164    return power;
165}
166
167double UidEntity::GetPowerForConnectivity(StatsUtils::StatsType statsType, int32_t uid)
168{
169    double power = StatsUtils::DEFAULT_VALUE;
170    auto bss = BatteryStatsService::GetInstance();
171    auto core = bss->GetBatteryStatsCore();
172    auto bluetoothEntity = core->GetEntity(BatteryStatsInfo::CONSUMPTION_TYPE_BLUETOOTH);
173
174    if (statsType == StatsUtils::STATS_TYPE_BLUETOOTH_BR_SCAN) {
175        power = bluetoothEntity->GetStatsPowerMah(StatsUtils::STATS_TYPE_BLUETOOTH_BR_SCAN, uid);
176    } else if (statsType == StatsUtils::STATS_TYPE_BLUETOOTH_BLE_SCAN) {
177        power = bluetoothEntity->GetStatsPowerMah(StatsUtils::STATS_TYPE_BLUETOOTH_BLE_SCAN, uid);
178    }
179    return power;
180}
181
182double UidEntity::GetPowerForCommon(StatsUtils::StatsType statsType, int32_t uid)
183{
184    double power = StatsUtils::DEFAULT_VALUE;
185    auto bss = BatteryStatsService::GetInstance();
186    auto core = bss->GetBatteryStatsCore();
187    auto cameraEntity = core->GetEntity(BatteryStatsInfo::CONSUMPTION_TYPE_CAMERA);
188    auto flashlightEntity = core->GetEntity(BatteryStatsInfo::CONSUMPTION_TYPE_FLASHLIGHT);
189    auto audioEntity = core->GetEntity(BatteryStatsInfo::CONSUMPTION_TYPE_AUDIO);
190    auto sensorEntity = core->GetEntity(BatteryStatsInfo::CONSUMPTION_TYPE_SENSOR);
191    auto gnssEntity = core->GetEntity(BatteryStatsInfo::CONSUMPTION_TYPE_GNSS);
192    auto cpuEntity = core->GetEntity(BatteryStatsInfo::CONSUMPTION_TYPE_CPU);
193    auto wakelockEntity = core->GetEntity(BatteryStatsInfo::CONSUMPTION_TYPE_WAKELOCK);
194    auto alarmEntity = core->GetEntity(BatteryStatsInfo::CONSUMPTION_TYPE_ALARM);
195
196    if (statsType == StatsUtils::STATS_TYPE_CAMERA_ON) {
197        power = cameraEntity->GetStatsPowerMah(StatsUtils::STATS_TYPE_CAMERA_ON, uid);
198    } else if (statsType == StatsUtils::STATS_TYPE_FLASHLIGHT_ON) {
199        power = flashlightEntity->GetStatsPowerMah(StatsUtils::STATS_TYPE_FLASHLIGHT_ON, uid);
200    } else if (statsType == StatsUtils::STATS_TYPE_GNSS_ON) {
201        power = gnssEntity->GetStatsPowerMah(StatsUtils::STATS_TYPE_GNSS_ON, uid);
202    } else if (statsType == StatsUtils::STATS_TYPE_SENSOR_GRAVITY_ON) {
203        power = sensorEntity->GetStatsPowerMah(StatsUtils::STATS_TYPE_SENSOR_GRAVITY_ON, uid);
204    } else if (statsType == StatsUtils::STATS_TYPE_SENSOR_PROXIMITY_ON) {
205        power = sensorEntity->GetStatsPowerMah(StatsUtils::STATS_TYPE_SENSOR_PROXIMITY_ON, uid);
206    } else if (statsType == StatsUtils::STATS_TYPE_AUDIO_ON) {
207        power = audioEntity->GetStatsPowerMah(StatsUtils::STATS_TYPE_AUDIO_ON, uid);
208    } else if (statsType == StatsUtils::STATS_TYPE_WAKELOCK_HOLD) {
209        power = wakelockEntity->GetStatsPowerMah(StatsUtils::STATS_TYPE_WAKELOCK_HOLD, uid);
210    } else if (statsType == StatsUtils::STATS_TYPE_CPU_CLUSTER) {
211        power = cpuEntity->GetStatsPowerMah(StatsUtils::STATS_TYPE_CPU_CLUSTER, uid);
212    } else if (statsType == StatsUtils::STATS_TYPE_CPU_SPEED) {
213        power = cpuEntity->GetStatsPowerMah(StatsUtils::STATS_TYPE_CPU_SPEED, uid);
214    } else if (statsType == StatsUtils::STATS_TYPE_CPU_ACTIVE) {
215        power = cpuEntity->GetStatsPowerMah(StatsUtils::STATS_TYPE_CPU_ACTIVE, uid);
216    } else if (statsType == StatsUtils::STATS_TYPE_ALARM) {
217        power = alarmEntity->GetStatsPowerMah(StatsUtils::STATS_TYPE_ALARM, uid);
218    }
219    return power;
220}
221
222double UidEntity::GetStatsPowerMah(StatsUtils::StatsType statsType, int32_t uid)
223{
224    double power = StatsUtils::DEFAULT_VALUE;
225
226    switch (statsType) {
227        case StatsUtils::STATS_TYPE_BLUETOOTH_BR_SCAN:
228        case StatsUtils::STATS_TYPE_BLUETOOTH_BLE_SCAN:
229            power = GetPowerForConnectivity(statsType, uid);
230            break;
231        case StatsUtils::STATS_TYPE_CAMERA_ON:
232        case StatsUtils::STATS_TYPE_FLASHLIGHT_ON:
233        case StatsUtils::STATS_TYPE_GNSS_ON:
234        case StatsUtils::STATS_TYPE_SENSOR_GRAVITY_ON:
235        case StatsUtils::STATS_TYPE_SENSOR_PROXIMITY_ON:
236        case StatsUtils::STATS_TYPE_AUDIO_ON:
237        case StatsUtils::STATS_TYPE_WAKELOCK_HOLD:
238        case StatsUtils::STATS_TYPE_CPU_CLUSTER:
239        case StatsUtils::STATS_TYPE_CPU_SPEED:
240        case StatsUtils::STATS_TYPE_CPU_ACTIVE:
241        case StatsUtils::STATS_TYPE_ALARM:
242            power = GetPowerForCommon(statsType, uid);
243            break;
244        default:
245            STATS_HILOGW(COMP_SVC, "Invalid or illegal type got, return 0");
246            break;
247    }
248
249    STATS_HILOGD(COMP_SVC, "Get %{public}s power: %{public}lfmAh for uid: %{public}d",
250        StatsUtils::ConvertStatsType(statsType).c_str(), power, uid);
251    return power;
252}
253
254void UidEntity::Reset()
255{
256    std::lock_guard<std::mutex> lock(uidEntityMutex_);
257    // Reset app Uid total power consumption
258    for (auto& iter : uidPowerMap_) {
259        iter.second = StatsUtils::DEFAULT_VALUE;
260    }
261}
262
263void UidEntity::DumpForBluetooth(int32_t uid, std::string& result)
264{
265    auto bss = BatteryStatsService::GetInstance();
266    // Dump for bluetooth realted info
267    auto core = bss->GetBatteryStatsCore();
268    int64_t bluetoothBrScanTime = core->GetTotalTimeMs(uid, StatsUtils::STATS_TYPE_BLUETOOTH_BR_SCAN);
269    int64_t bluetoothBleScanTime = core->GetTotalTimeMs(uid, StatsUtils::STATS_TYPE_BLUETOOTH_BLE_SCAN);
270
271    result.append("Bluetooth Br scan time: ")
272        .append(ToString(bluetoothBrScanTime))
273        .append("ms\n")
274        .append("Bluetooth Ble scan time: ")
275        .append(ToString(bluetoothBleScanTime))
276        .append("ms\n");
277}
278
279void UidEntity::DumpForCommon(int32_t uid, std::string& result)
280{
281    auto bss = BatteryStatsService::GetInstance();
282    auto core = bss->GetBatteryStatsCore();
283    // Dump for camera related info
284    int64_t cameraTime = core->GetTotalTimeMs(uid, StatsUtils::STATS_TYPE_CAMERA_ON);
285
286    // Dump for flashlight related info
287    int64_t flashlightTime = core->GetTotalTimeMs(uid, StatsUtils::STATS_TYPE_FLASHLIGHT_ON);
288
289    // Dump for gnss related info
290    int64_t gnssTime = core->GetTotalTimeMs(uid, StatsUtils::STATS_TYPE_GNSS_ON);
291
292    // Dump for gravity sensor related info
293    int64_t gravityTime = core->GetTotalTimeMs(uid, StatsUtils::STATS_TYPE_SENSOR_GRAVITY_ON);
294
295    // Dump for proximity sensor related info
296    int64_t proximityTime = core->GetTotalTimeMs(uid, StatsUtils::STATS_TYPE_SENSOR_PROXIMITY_ON);
297
298    // Dump for audio related info
299    int64_t audioTime = core->GetTotalTimeMs(uid, StatsUtils::STATS_TYPE_AUDIO_ON);
300
301    // Dump for wakelock related info
302    int64_t wakelockTime = core->GetTotalTimeMs(uid, StatsUtils::STATS_TYPE_WAKELOCK_HOLD);
303
304    // Dump for alarm related info
305    int64_t alarmCount = core->GetTotalConsumptionCount(StatsUtils::STATS_TYPE_ALARM, uid);
306
307    result.append("Camera on time: ")
308        .append(ToString(cameraTime))
309        .append("ms\n")
310        .append("Flashlight scan time: ")
311        .append(ToString(flashlightTime))
312        .append("ms\n")
313        .append("GNSS scan time: ")
314        .append(ToString(gnssTime))
315        .append("ms\n")
316        .append("Gravity sensor on time: ")
317        .append(ToString(gravityTime))
318        .append("ms\n")
319        .append("Proximity sensor on time: ")
320        .append(ToString(proximityTime))
321        .append("ms\n")
322        .append("Audio on time: ")
323        .append(ToString(audioTime))
324        .append("ms\n")
325        .append("Wakelock hold time: ")
326        .append(ToString(wakelockTime))
327        .append("ms\n")
328        .append("Alarm trigger count: ")
329        .append(ToString(alarmCount))
330        .append("times\n");
331}
332
333void UidEntity::DumpInfo(std::string& result, int32_t uid)
334{
335    auto bss = BatteryStatsService::GetInstance();
336    std::lock_guard<std::mutex> lock(uidEntityMutex_);
337    auto core = bss->GetBatteryStatsCore();
338    for (auto& iter : uidPowerMap_) {
339        std::string bundleName = "NULL";
340#ifdef SYS_MGR_CLIENT_ENABLE
341        auto bundleObj =
342            DelayedSingleton<AppExecFwk::SysMrgClient>::GetInstance()
343                ->GetSystemAbility(BUNDLE_MGR_SERVICE_SYS_ABILITY_ID);
344        if (bundleObj == nullptr) {
345            STATS_HILOGE(COMP_SVC, "Failed to get bundle manager service");
346        } else {
347            sptr<AppExecFwk::IBundleMgr> bmgr = iface_cast<AppExecFwk::IBundleMgr>(bundleObj);
348            if (bmgr == nullptr) {
349                STATS_HILOGE(COMP_SVC, "Failed to get bundle manager proxy");
350            } else {
351                std::string identity = IPCSkeleton::ResetCallingIdentity();
352                ErrCode res = bmgr->GetNameForUid(iter.first, bundleName);
353                IPCSkeleton::SetCallingIdentity(identity);
354                if (res != ERR_OK) {
355                    STATS_HILOGE(COMP_SVC, "Failed to get bundle name for uid=%{public}d, ErrCode=%{public}d",
356                        iter.first, static_cast<int32_t>(res));
357                }
358            }
359        }
360#endif
361        result.append("\n")
362            .append(ToString(iter.first))
363            .append("(Bundle name: ")
364            .append(bundleName)
365            .append(")")
366            .append(":")
367            .append("\n");
368        DumpForBluetooth(iter.first, result);
369        DumpForCommon(iter.first, result);
370        auto cpuEntity = core->GetEntity(BatteryStatsInfo::CONSUMPTION_TYPE_CPU);
371        if (cpuEntity) {
372            cpuEntity->DumpInfo(result, iter.first);
373        }
374    }
375}
376} // namespace PowerMgr
377} // namespace OHOS