您好,登錄后才能下訂單哦!
這篇文章主要介紹了android5.1中healthd的示例分析,具有一定借鑒價值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓小編帶著大家一起了解一下。
healthd主要是讀取電池節點的信息,傳給BatteryService。或者在關機充電等使用。注意healthd中使用的是kernel的log。
下面先從main函數分析
int main(int argc, char **argv) { int ch; int ret; klog_set_level(KLOG_LEVEL); healthd_mode_ops = &android_ops; if (!strcmp(basename(argv[0]), "charger")) {//解析輸入參數如果是charger的使用charger_ops,這里就不做介紹 healthd_mode_ops = &charger_ops; } else { while ((ch = getopt(argc, argv, "cr")) != -1) {//分析輸入命令,各個命令對應不同的charger_ops switch (ch) { case 'c': healthd_mode_ops = &charger_ops; break; case 'r': healthd_mode_ops = &recovery_ops; break; case '?': default: KLOG_ERROR(LOG_TAG, "Unrecognized healthd option: %c\n", optopt); exit(1); } } } ret = healthd_init();//healthd做初始化 if (ret) { KLOG_ERROR("Initialization failed, exiting\n"); exit(2); } healthd_mainloop();//主函數 KLOG_ERROR("Main loop terminated, exiting\n"); return 3; }
如果是正常開機,不走關機充電等,healthd_mode_ops = &android_ops;而這里面具體的函數在后面進行詳細的介紹。
static struct healthd_mode_ops android_ops = { .init = healthd_mode_android_init, .preparetowait = healthd_mode_android_preparetowait, .heartbeat = healthd_mode_nop_heartbeat, .battery_update = healthd_mode_android_battery_update, };
下面分析下healthd_init函數,heathd使用了epoll進行IO復用。
static int healthd_init() { epollfd = epoll_create(MAX_EPOLL_EVENTS); if (epollfd == -1) { KLOG_ERROR(LOG_TAG, "epoll_create failed; errno=%d\n", errno); return -1; } healthd_board_init(&healthd_config); healthd_mode_ops->init(&healthd_config); wakealarm_init(); uevent_init(); gBatteryMonitor = new BatteryMonitor(); gBatteryMonitor->init(&healthd_config); return 0; }
這里的healthd_mode_ops->init的函數是android_ops 的healthd_mode_android_init函數,這里主要是將binder通信的fd也加入epoll,而不像普通binder進程最后使用IPCThreadState::self()->joinThreadPool。這樣所有的fd全在epoll管理,只用了一個線程
int healthd_mode_android_preparetowait(void) { IPCThreadState::self()->flushCommands(); return -1; } static void binder_event(uint32_t /*epevents*/) { IPCThreadState::self()->handlePolledCommands(); } void healthd_mode_android_init(struct healthd_config* /*config*/) { ProcessState::self()->setThreadPoolMaxThreadCount(0); IPCThreadState::self()->disableBackgroundScheduling(true); IPCThreadState::self()->setupPolling(&gBinderFd); if (gBinderFd >= 0) { if (healthd_register_event(gBinderFd, binder_event)) KLOG_ERROR(LOG_TAG, "Register for binder events failed\n"); } gBatteryPropertiesRegistrar = new BatteryPropertiesRegistrar(); gBatteryPropertiesRegistrar->publish(); }
gBatteryPropertiesRegistrar->publish將"batteryproperties"這個Service加入到ServiceManager中
void BatteryPropertiesRegistrar::publish() { defaultServiceManager()->addService(String16("batteryproperties"), this); }
接下來再來看下wakealarm_init
static void wakealarm_init(void) { wakealarm_fd = timerfd_create(CLOCK_BOOTTIME_ALARM, TFD_NONBLOCK); if (wakealarm_fd == -1) { KLOG_ERROR(LOG_TAG, "wakealarm_init: timerfd_create failed\n"); return; } if (healthd_register_event(wakealarm_fd, wakealarm_event)) KLOG_ERROR(LOG_TAG, "Registration of wakealarm event failed\n"); wakealarm_set_interval(healthd_config.periodic_chores_interval_fast); }
wakealarm_init設置alarm喚醒的interval,再來看下時間處理函數
static void wakealarm_event(uint32_t /*epevents*/) { unsigned long long wakeups; if (read(wakealarm_fd, &wakeups, sizeof(wakeups)) == -1) {//出錯結束 KLOG_ERROR(LOG_TAG, "wakealarm_event: read wakealarm fd failed\n"); return; } KLOG_ERROR(LOG_TAG, "wakealarm_event\n"); periodic_chores(); }
static void periodic_chores() { healthd_battery_update(); }
void healthd_battery_update(void) { // Fast wake interval when on charger (watch for overheat); // slow wake interval when on battery (watch for drained battery). KLOG_ERROR(LOG_TAG, "healthd_battery_update enter\n"); int new_wake_interval = gBatteryMonitor->update() ?//調用主要的update函數,根據返回值,如果當前在充電返回true healthd_config.periodic_chores_interval_fast ://時間設置1分鐘 healthd_config.periodic_chores_interval_slow; KLOG_ERROR(LOG_TAG, "healthd_battery_update after\n"); if (new_wake_interval != wakealarm_wake_interval) wakealarm_set_interval(new_wake_interval); // During awake periods poll at fast rate. If wake alarm is set at fast // rate then just use the alarm; if wake alarm is set at slow rate then // poll at fast rate while awake and let alarm wake up at slow rate when // asleep. if (healthd_config.periodic_chores_interval_fast == -1) awake_poll_interval = -1; else awake_poll_interval = new_wake_interval == healthd_config.periodic_chores_interval_fast ?//當前時間是一分鐘,epoll為永遠阻塞,否則為1分鐘 -1 : healthd_config.periodic_chores_interval_fast * 1000; }
接下來再來看看uEvent的,
static void uevent_init(void) { uevent_fd = uevent_open_socket(64*1024, true); if (uevent_fd < 0) { KLOG_ERROR(LOG_TAG, "uevent_init: uevent_open_socket failed\n"); return; } fcntl(uevent_fd, F_SETFL, O_NONBLOCK); if (healthd_register_event(uevent_fd, uevent_event)) KLOG_ERROR(LOG_TAG, "register for uevent events failed\n"); }
看看uevent_event的處理函數,獲取uevent后主要判斷是否是電源系統的,如果是調用healthd_battery_update函數
static void uevent_event(uint32_t /*epevents*/) { char msg[UEVENT_MSG_LEN+2]; char *cp; int n; n = uevent_kernel_multicast_recv(uevent_fd, msg, UEVENT_MSG_LEN); if (n <= 0) return; if (n >= UEVENT_MSG_LEN) /* overflow -- discard */ return; msg[n] = '\0'; msg[n+1] = '\0'; cp = msg; KLOG_ERROR(LOG_TAG, "uevent_event\n"); while (*cp) { if (!strcmp(cp, "SUBSYSTEM=" POWER_SUPPLY_SUBSYSTEM)) {//是這個子系統的調用healthd_battery_update函數 healthd_battery_update(); break; } /* advance to after the next \0 */ while (*cp++) ; } }
下面分析下healthd_mainloop這個主函數,主函數主要是epoll函數監聽3個fd,有事件就處理。
static void healthd_mainloop(void) { while (1) { struct epoll_event events[eventct]; int nevents; int timeout = awake_poll_interval; int mode_timeout; mode_timeout = healthd_mode_ops->preparetowait(); if (timeout < 0 || (mode_timeout > 0 && mode_timeout < timeout)) timeout = mode_timeout; nevents = epoll_wait(epollfd, events, eventct, timeout);//epoll_wait等待各個fd的事件,timeout為超時時間 KLOG_ERROR(LOG_TAG, "kangchen healthd_mainloop epoll_wait\n"); if (nevents == -1) { if (errno == EINTR) continue; KLOG_ERROR(LOG_TAG, "healthd_mainloop: epoll_wait failed\n"); break; } for (int n = 0; n < nevents; ++n) { if (events[n].data.ptr)//遍歷各個fd的事件上來,每個處理函數處理 (*(void (*)(int))events[n].data.ptr)(events[n].events); } if (!nevents)//當什么事件沒有的時候,是因為epoll超時設置走下來的,這時候也要update下 periodic_chores(); healthd_mode_ops->heartbeat(); } return; }
init函數主要將healthd_config 對象傳入,并且將里面的成員的一些地址信息去初始化保存起來。主要是保存一些地址信息,以及充電方式。
void BatteryMonitor::init(struct healthd_config *hc) { String8 path; char pval[PROPERTY_VALUE_MAX]; mHealthdConfig = hc;//將外面傳進來的heathdconfig的指針賦給成員變量 DIR* dir = opendir(POWER_SUPPLY_SYSFS_PATH);//打開地址 /sys/class/power_supply if (dir == NULL) { KLOG_ERROR(LOG_TAG, "Could not open %s\n", POWER_SUPPLY_SYSFS_PATH); } else { struct dirent* entry; while ((entry = readdir(dir))) { const char* name = entry->d_name; if (!strcmp(name, ".") || !strcmp(name, "..")) continue; char buf[20]; // Look for "type" file in each subdirectory path.clear(); path.appendFormat("%s/%s/type", POWER_SUPPLY_SYSFS_PATH, name); switch(readPowerSupplyType(path)) {//讀取各個目錄下type的值,比如/sys/class/power_supply/battery 下type的值為Battery,在readPowerSupplyType讀取并且轉化為ANDROID_POWER_SUPPLY_TYPE_BATTERY case ANDROID_POWER_SUPPLY_TYPE_AC: if (mHealthdConfig->acChargeHeathPath.isEmpty()) { path.clear(); path.appendFormat("%s/%s/health", POWER_SUPPLY_SYSFS_PATH, name); if (access(path, R_OK) == 0) mHealthdConfig->acChargeHeathPath = path;//配置路徑 } path.clear(); path.appendFormat("%s/%s/online", POWER_SUPPLY_SYSFS_PATH, name); if (access(path.string(), R_OK) == 0) mChargerNames.add(String8(name));//chargername 就是當前目錄名字:ac break; case ANDROID_POWER_SUPPLY_TYPE_USB://usb 類似ac if (mHealthdConfig->usbChargeHeathPath.isEmpty()) { path.clear(); path.appendFormat("%s/%s/health", POWER_SUPPLY_SYSFS_PATH, name); if (access(path, R_OK) == 0) mHealthdConfig->usbChargeHeathPath = path; } path.clear(); path.appendFormat("%s/%s/online", POWER_SUPPLY_SYSFS_PATH, name); if (access(path.string(), R_OK) == 0) mChargerNames.add(String8(name)); break; case ANDROID_POWER_SUPPLY_TYPE_WIRELESS://類似 path.clear(); path.appendFormat("%s/%s/online", POWER_SUPPLY_SYSFS_PATH, name); if (access(path.string(), R_OK) == 0) mChargerNames.add(String8(name)); break; case ANDROID_POWER_SUPPLY_TYPE_BATTERY://battery mBatteryDevicePresent = true; if (mHealthdConfig->batteryStatusPath.isEmpty()) { path.clear(); path.appendFormat("%s/%s/status", POWER_SUPPLY_SYSFS_PATH, name); if (access(path, R_OK) == 0) mHealthdConfig->batteryStatusPath = path; } if (mHealthdConfig->batteryHealthPath.isEmpty()) { path.clear(); path.appendFormat("%s/%s/health", POWER_SUPPLY_SYSFS_PATH, name); if (access(path, R_OK) == 0) mHealthdConfig->batteryHealthPath = path; } if (mHealthdConfig->batteryPresentPath.isEmpty()) { path.clear(); path.appendFormat("%s/%s/present", POWER_SUPPLY_SYSFS_PATH, name); if (access(path, R_OK) == 0) mHealthdConfig->batteryPresentPath = path; } if (mHealthdConfig->batteryCapacityPath.isEmpty()) { path.clear(); path.appendFormat("%s/%s/capacity", POWER_SUPPLY_SYSFS_PATH, name); if (access(path, R_OK) == 0) mHealthdConfig->batteryCapacityPath = path; } if (mHealthdConfig->batteryVoltagePath.isEmpty()) { path.clear(); path.appendFormat("%s/%s/voltage_now", POWER_SUPPLY_SYSFS_PATH, name); if (access(path, R_OK) == 0) { mHealthdConfig->batteryVoltagePath = path; } else { path.clear(); path.appendFormat("%s/%s/batt_vol", POWER_SUPPLY_SYSFS_PATH, name); if (access(path, R_OK) == 0) mHealthdConfig->batteryVoltagePath = path; } } if (mHealthdConfig->batteryCurrentNowPath.isEmpty()) { path.clear(); path.appendFormat("%s/%s/current_now", POWER_SUPPLY_SYSFS_PATH, name); if (access(path, R_OK) == 0) mHealthdConfig->batteryCurrentNowPath = path; } if (mHealthdConfig->batteryCurrentAvgPath.isEmpty()) { path.clear(); path.appendFormat("%s/%s/current_avg", POWER_SUPPLY_SYSFS_PATH, name); if (access(path, R_OK) == 0) mHealthdConfig->batteryCurrentAvgPath = path; } if (mHealthdConfig->batteryChargeCounterPath.isEmpty()) { path.clear(); path.appendFormat("%s/%s/charge_counter", POWER_SUPPLY_SYSFS_PATH, name); if (access(path, R_OK) == 0) mHealthdConfig->batteryChargeCounterPath = path; } if (mHealthdConfig->batteryTemperaturePath.isEmpty()) { path.clear(); path.appendFormat("%s/%s/temp", POWER_SUPPLY_SYSFS_PATH, name); if (access(path, R_OK) == 0) { mHealthdConfig->batteryTemperaturePath = path; } else { path.clear(); path.appendFormat("%s/%s/batt_temp", POWER_SUPPLY_SYSFS_PATH, name); if (access(path, R_OK) == 0) mHealthdConfig->batteryTemperaturePath = path; } } if (mHealthdConfig->batteryTechnologyPath.isEmpty()) { path.clear(); path.appendFormat("%s/%s/technology", POWER_SUPPLY_SYSFS_PATH, name); if (access(path, R_OK) == 0) mHealthdConfig->batteryTechnologyPath = path; } break; case ANDROID_POWER_SUPPLY_TYPE_UNKNOWN: break; } } closedir(dir); } if (!mChargerNames.size()) KLOG_ERROR(LOG_TAG, "No charger supplies found\n"); if (!mBatteryDevicePresent) {//主要由battery該成員變量就為true KLOG_WARNING(LOG_TAG, "No battery devices found\n"); hc->periodic_chores_interval_fast = -1; hc->periodic_chores_interval_slow = -1; } else { if (mHealthdConfig->batteryStatusPath.isEmpty()) KLOG_WARNING(LOG_TAG, "BatteryStatusPath not found\n"); 。。。。。。。。。。。。。//這里都是一些警告 } if (property_get("ro.boot.fake_battery", pval, NULL) > 0 && strtol(pval, NULL, 10) != 0) { mBatteryFixedCapacity = FAKE_BATTERY_CAPACITY; mBatteryFixedTemperature = FAKE_BATTERY_TEMPERATURE; } }
下面就是update函數,將數據封裝在BatteryProperties 中,并且通過healthd_mode_ops->battery_update把BatteryProperties 發給上層。
bool BatteryMonitor::update(void) { bool logthis; props.chargerAcOnline = false; props.chargerUsbOnline = false; props.chargerWirelessOnline = false; props.batteryStatus = BATTERY_STATUS_UNKNOWN; props.batteryHealth = BATTERY_HEALTH_UNKNOWN; //都是從之前配置的mHealthd中取地址,讀取節點信息,保存到props成員變量中 if (!mHealthdConfig->batteryPresentPath.isEmpty()) props.batteryPresent = getBooleanField(mHealthdConfig->batteryPresentPath); else props.batteryPresent = mBatteryDevicePresent; props.batteryLevel = mBatteryFixedCapacity ? mBatteryFixedCapacity : getIntField(mHealthdConfig->batteryCapacityPath); props.batteryVoltage = getIntField(mHealthdConfig->batteryVoltagePath) / 1000; props.batteryTemperature = mBatteryFixedTemperature ? mBatteryFixedTemperature : getIntField(mHealthdConfig->batteryTemperaturePath); const int SIZE = 128; char buf[SIZE]; String8 btech; if (readFromFile(mHealthdConfig->batteryStatusPath, buf, SIZE) > 0) props.batteryStatus = getBatteryStatus(buf); if (readFromFile(mHealthdConfig->batteryHealthPath, buf, SIZE) > 0) props.batteryHealth = getBatteryHealth(buf); if (readFromFile(mHealthdConfig->batteryTechnologyPath, buf, SIZE) > 0) props.batteryTechnology = String8(buf); if (readFromFile(mHealthdConfig->acChargeHeathPath, buf, SIZE) > 0) props.acChargeHeath= String8(buf); if (readFromFile(mHealthdConfig->usbChargeHeathPath, buf, SIZE) > 0) props.usbChargeHeath= String8(buf); unsigned int i; for (i = 0; i < mChargerNames.size(); i++) {//遍歷之前保存的各個充電方式 String8 path; path.appendFormat("%s/%s/online", POWER_SUPPLY_SYSFS_PATH, mChargerNames[i].string());//路徑就是每個目錄下的online字段,比如/sys/class/power_supply/usb 下的online if (readFromFile(path, buf, SIZE) > 0) { if (buf[0] != '0') {//讀取online里面的內容,如果當前在usb線上充電,那么usb下online里面的內容為1 path.clear(); path.appendFormat("%s/%s/type", POWER_SUPPLY_SYSFS_PATH, mChargerNames[i].string());//這里看看是哪個type的 switch(readPowerSupplyType(path)) { case ANDROID_POWER_SUPPLY_TYPE_AC: props.chargerAcOnline = true; break; case ANDROID_POWER_SUPPLY_TYPE_USB://將其值賦成true props.chargerUsbOnline = true; break; case ANDROID_POWER_SUPPLY_TYPE_WIRELESS: props.chargerWirelessOnline = true; break; default: KLOG_WARNING(LOG_TAG, "%s: Unknown power supply type\n", mChargerNames[i].string()); } } } } logthis = !healthd_board_battery_update(&props); if (logthis) { char dmesgline[256]; if (props.batteryPresent) { snprintf(dmesgline, sizeof(dmesgline), "battery l=%d v=%d t=%s%d.%d h=%d st=%d", props.batteryLevel, props.batteryVoltage, props.batteryTemperature < 0 ? "-" : "", abs(props.batteryTemperature / 10), abs(props.batteryTemperature % 10), props.batteryHealth, props.batteryStatus); if (!mHealthdConfig->batteryCurrentNowPath.isEmpty()) { int c = getIntField(mHealthdConfig->batteryCurrentNowPath); char b[20]; snprintf(b, sizeof(b), " c=%d", c / 1000); strlcat(dmesgline, b, sizeof(dmesgline)); } } else { snprintf(dmesgline, sizeof(dmesgline), "battery none"); } KLOG_WARNING(LOG_TAG, "%s chg=%s%s%s\n", dmesgline, props.chargerAcOnline ? "a" : "", props.chargerUsbOnline ? "u" : "", props.chargerWirelessOnline ? "w" : ""); } healthd_mode_ops->battery_update(&props);//將數據傳到上層的BatteryService return props.chargerAcOnline | props.chargerUsbOnline |//返回當前是否屬于充電 props.chargerWirelessOnline; }
接下來看看healthd_mode_ops->battery_update是怎么把數據傳到上層的
void healthd_mode_android_battery_update( struct android::BatteryProperties *props) { if (gBatteryPropertiesRegistrar != NULL) gBatteryPropertiesRegistrar->notifyListeners(*props); return; }
上層會通過binder通信,注冊一個回調到BatteryPropertiesRegistrar
void BatteryPropertiesRegistrar::registerListener(const sp<IBatteryPropertiesListener>& listener) { { if (listener == NULL) return; Mutex::Autolock _l(mRegistrationLock); // check whether this is a duplicate for (size_t i = 0; i < mListeners.size(); i++) { if (mListeners[i]->asBinder() == listener->asBinder()) { return; } } mListeners.add(listener); listener->asBinder()->linkToDeath(this); } healthd_battery_update(); }
而update函數就是調用了notifyListeners遍歷各個listener傳到上層BatteryService
void BatteryPropertiesRegistrar::notifyListeners(struct BatteryProperties props) { Mutex::Autolock _l(mRegistrationLock); for (size_t i = 0; i < mListeners.size(); i++) { mListeners[i]->batteryPropertiesChanged(props); } }
再來看看BatteryService中,在onStart中通過ServiceManager,和batteryproperties這個Service通信,將BatteryListener這個listenter注冊到batteryproperties中去
@Override public void onStart() { IBinder b = ServiceManager.getService("batteryproperties"); final IBatteryPropertiesRegistrar batteryPropertiesRegistrar = IBatteryPropertiesRegistrar.Stub.asInterface(b); try { batteryPropertiesRegistrar.registerListener(new BatteryListener()); } catch (RemoteException e) { // Should never happen. } publishBinderService("battery", new BinderService()); publishLocalService(BatteryManagerInternal.class, new LocalService()); }
再來看看BatteryListener 的batteryPropertiesChanged接口,當下面調這個接口,就會調用BatteryService的update函數,然后就是BatteryService的一些主要流程就不分析了。
private final class BatteryListener extends IBatteryPropertiesListener.Stub { @Override public void batteryPropertiesChanged(BatteryProperties props) { final long identity = Binder.clearCallingIdentity(); try { BatteryService.this.update(props); } finally { Binder.restoreCallingIdentity(identity); } } }
BatteryService接受healthd的數據都是被動的,healthd穿過來的。有沒有主動去healthd查詢的。
在BatteryManager中就有主動去healthd查詢的,代碼如下
private long queryProperty(int id) { long ret; if (mBatteryPropertiesRegistrar == null) { IBinder b = ServiceManager.getService("batteryproperties");//獲取batteryproperties Service mBatteryPropertiesRegistrar = IBatteryPropertiesRegistrar.Stub.asInterface(b);//接口轉化下 if (mBatteryPropertiesRegistrar == null) return Long.MIN_VALUE; } try { BatteryProperty prop = new BatteryProperty(); if (mBatteryPropertiesRegistrar.getProperty(id, prop) == 0)//prop是輸出 ret = prop.getLong(); else ret = Long.MIN_VALUE; } catch (RemoteException e) { ret = Long.MIN_VALUE; } return ret; }
再到healthd看看對應的接口
status_t BatteryPropertiesRegistrar::getProperty(int id, struct BatteryProperty *val) { return healthd_get_property(id, val); }
status_t healthd_get_property(int id, struct BatteryProperty *val) { return gBatteryMonitor->getProperty(id, val); }
java的BatteryProperty對象對應到這邊是指針
status_t BatteryMonitor::getProperty(int id, struct BatteryProperty *val) { status_t ret = BAD_VALUE; val->valueInt64 = LONG_MIN; switch(id) { case BATTERY_PROP_CHARGE_COUNTER://根據不同ID,返回不同值 if (!mHealthdConfig->batteryChargeCounterPath.isEmpty()) { val->valueInt64 = getIntField(mHealthdConfig->batteryChargeCounterPath); ret = NO_ERROR; } else { ret = NAME_NOT_FOUND; } break; case BATTERY_PROP_CURRENT_NOW: if (!mHealthdConfig->batteryCurrentNowPath.isEmpty()) { val->valueInt64 = getIntField(mHealthdConfig->batteryCurrentNowPath); ret = NO_ERROR; } else { ret = NAME_NOT_FOUND; } break; case BATTERY_PROP_CURRENT_AVG: if (!mHealthdConfig->batteryCurrentAvgPath.isEmpty()) { val->valueInt64 = getIntField(mHealthdConfig->batteryCurrentAvgPath); ret = NO_ERROR; } else { ret = NAME_NOT_FOUND; } break; case BATTERY_PROP_CAPACITY: if (!mHealthdConfig->batteryCapacityPath.isEmpty()) { val->valueInt64 = getIntField(mHealthdConfig->batteryCapacityPath); ret = NO_ERROR; } else { ret = NAME_NOT_FOUND; } break; case BATTERY_PROP_ENERGY_COUNTER: if (mHealthdConfig->energyCounter) { ret = mHealthdConfig->energyCounter(&val->valueInt64); } else { ret = NAME_NOT_FOUND; } break; default: break; } return ret; }
感謝你能夠認真閱讀完這篇文章,希望小編分享的“android5.1中healthd的示例分析”這篇文章對大家有幫助,同時也希望大家多多支持億速云,關注億速云行業資訊頻道,更多相關知識等著你來學習!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。