1. 程式人生 > >獲取支援SRIOV的網路介面裝置資訊

獲取支援SRIOV的網路介面裝置資訊

1.首先 virsh nodedev-list --cap net | grep -v net_lo_00_00_00_00_00_00 可以檢視當前系統現有的網路裝置 如下圖所示
2.但是上述只能顯示裝置資訊,無法顯示出裝置的pci相關資訊,也可以virsh nodedev-list --tree 以樹形的結構展現 以樹形結構展現 可以展現對應pci資訊下的裝置資訊
3.virsh nodedev-list dumpxml 某個裝置名字如 net_enp8s16f5_6e_36_5a_d1_e3_a3可以得到如下資訊
4.可以看到該網路裝置的硬體資訊 如網絡卡名字和MAC地址等,其parent一項指定的pci資訊也正好是樹形結構下該裝置對應的pci資訊 執行 virsh nodedev-list dumpxml  pci_0000_08_10_5 可得到如下資訊

5.圖中描述的不再是具體的裝置資訊,二是裝置對應的pci相關資訊和對應的網絡卡及驅動資訊,該網路裝置是SRIOV環境下一個物理PF虛擬出的一個VF,所以name 一項是igbvf  6.下面再看物理網路介面 virsh nodedev-dumpxml net_enp7s0f0_f8_0f_41_f2_ea_ee 可以得到物理網路介面裝置的相關資訊,MAC和介面速度等   7.之後對應其pci 資訊 virsh nodedev-dumpxml pci_0000_07_00_0
可以看出該物理網路裝置對應的網絡卡驅動資訊,並且由於配置了其支援SRIOV可以看到其上虛擬出來的各個VF的PCI資訊,每個VF PCI資訊下都對應一個VF相關資訊,因而可以將這些資訊整合,形成一個直觀的支援SRIOV的系統的網路介面裝置資訊,最後形式如下

程式碼如下: #!/bin/bash ## # Copyright 2015 Telefónica Investigación y Desarrollo, S.A.U. # This file is part of openmano # All Rights Reserved. # # 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. # # For those usages not covered by the Apache License, Version 2.0 please # contact with:
[email protected]
## #Get configuration of a host for using it as a compute node #### ###author wangxia ctbri [email protected] ###system:CentOS Linux release 7.2.1511 (Core) ###NIC:I350 Gigabit Network Connection ###NIC driver:igb #### function usage(){     echo  -e "usage: $0 user ip_name [>> host.yaml]\n  Get host parameters and generated a yaml file to be used for openvim host-add"     exit 1 } function load_vf_driver(){   local pf_driver=$1   if [[ `lsmod | cut -d" " -f1 | grep $pf_driver | grep -v vf` ]] && [[ ! `lsmod | cut -d" " -f1 | grep ${pf_driver}vf` ]]   then     >&2 echo "$pf_driver is loaded but not ${pf_driver}vf. This is required in order to properly add SR-IOV."     read -p "Do you want to load ${pf_driver}vf [Y/n] " load_driver     case $load_driver in       [nN]* ) exit 1;;       * ) >&2 echo "Loading ${pf_driver}vf..."           modprobe ${pf_driver}vf;           >&2 echo "Reloading ${pf_driver}..."           modprobe -r $pf_driver;           modprobe $pf_driver;;     esac   fi } function remove_vf_driver(){   local pf_driver=$1   if [[ `lsmod | cut -d" " -f1 | grep $pf_driver | grep -v vf` ]] && [[ `lsmod | cut -d" " -f1 | grep ${pf_driver}vf` ]]   then     >&2 echo "${pf_driver}vf is loaded. In order to ensure proper SR-IOV behavior the driver must be removed."     read -p "Do you want to remove ${pf_driver}vf now? [Y/n] " remove_driver     case $remove_driver in       [nN]* ) >&2 echo "OK. Remember to remove the driver prior start using the compute node executing:";               >&2 echo "modprobe -r ${pf_driver}vf";               >&2 echo "modprobe -r ${pf_driver}";               >&2 echo "modprobe ${pf_driver}";;       * ) >&2 echo "Removing ${pf_driver}vf..."           modprobe -r ${pf_driver}vf;           >&2 echo "Reloading ${pf_driver}..."           modprobe -r $pf_driver;           modprobe $pf_driver;;     esac   fi } function get_hash_value() {   echo `eval  echo $\{\`echo $1[$2]\`\}`; } function xmlpath_args() {   local expr="${1//\// }"   local path=()   local chunk tag data   local exit_code=1   local print_line=0   local closing_tag=0   while IFS='' read -r -d '<' chunk; do     data=arguments=""     IFS='>' read -r tag_arg data <<< "$chunk"     IFS=' ' read -r tag arguments <<< "$tag_arg"     #If last tag was single level remove it from path     if [[ $closing_tag -eq 1 ]]     then       unset path[${#path[@]}-1]       closing_tag=0     fi     #In case the tag is closed in the same line mark it     [[ $arguments = ?*'/' ]] && closing_tag=1     arguments="${arguments//\//}"     case "$tag" in       '?'*) ;;       '!--'*) ;;       ?*'/') ;;       '/'?*) unset path[${#path[@]}-1] ;;       ?*) path+=("$tag");;            esac     #echo "\"${path[@]}\" \"$expr\" \"$data\" \"$arguments\" $exit_code $print_line"     if [[ "${path[@]}" == "$expr" ]]     then       #If there is data print it and append arguments if any       if [ "$data" != "" ]       then         echo "$data $arguments"         #return code 0 means data was found         exit_code=0         continue       #if there is no data but there are arguments print arguments       elif [ "$arguments" != "" ]       then         echo "$arguments"         #return code 2 means no data but arguments were found         exit_code=2         continue       #otherwise switch flag to start/stop echoing each line until the tag is closed       elif [[ $exit_code -eq 1 ]]       then         print_line=$(((print_line+1)%2))         #return code 3 means that the whole xml segment is returned         exit_code=3       fi     fi     [[ $print_line == "1" ]] && echo "<"$chunk   done   return $exit_code } #check root privileges and non a root user behind [[ "$#" -lt "2" ]] && echo "Missing parameters" && usage #load_vf_driver ixgbe load_vf_driver igb HOST_NAME=`cat /etc/hostname` FEATURES=`grep "^flags"  /proc/cpuinfo` FEATURES_LIST="" if echo $FEATURES | grep -q pdpe1gb ; then FEATURES_LIST="${FEATURES_LIST},lps";  fi if echo $FEATURES | grep -q dca     ; then FEATURES_LIST="${FEATURES_LIST},dioc"; fi if echo $FEATURES | egrep -q "(vmx|svm)" ; then FEATURES_LIST="${FEATURES_LIST},hwsv"; fi if echo $FEATURES | egrep -q "(ept|npt)" ; then FEATURES_LIST="${FEATURES_LIST},tlbps"; fi if echo $FEATURES | grep -q ht      ; then FEATURES_LIST="${FEATURES_LIST},ht";   fi if uname -m | grep -q x86_64        ; then FEATURES_LIST="${FEATURES_LIST},64b";  fi if cat /var/log/dmesg | grep -q -e Intel-IOMMU   ; then FEATURES_LIST="${FEATURES_LIST},iommu";  fi FEATURES_LIST=${FEATURES_LIST#,} NUMAS=`gawk 'BEGIN{numas=0;}   ($1=="physical" && $2=="id" ){ if ($4+1>numas){numas=$4+1} };   END{printf("%d",numas);}' /proc/cpuinfo` CPUS=`gawk '($1=="processor"){pro=$3;}   ($1=="physical" && $2=="id"){ phy=$4;}   ($1=="core" && $2=="id"){printf " %d-%d-%d", phy,$4,pro;}' /proc/cpuinfo` if grep -q isolcpus /proc/cmdline then   isolcpus=`cat /proc/cmdline`   isolcpus=${isolcpus##*isolcpus=}   isolcpus=${isolcpus%% *}   isolcpus=${isolcpus//,/ } else   isolcpus="" fi #obtain interfaces information unset dpid read -p "Do you want to provide the interfaces connectivity information (datapathid/dpid of the switch and switch port id)? [Y/n] " conn_info case $conn_info in     [Nn]* ) prov_conn=false;;     * ) prov_conn=true;         read -p "What is the switch dapapathid/dpdi? (01:02:03:04:05:06:07:08) " dpid;         [[ -z $dpid ]] && dpid="01:02:03:04:05:06:07:08";         PORT_RANDOM=$RANDOM         iface_counter=0;; esac        OLDIFS=$IFS IFS=$'\n' unset PF_list unset VF_list for device in `virsh nodedev-list --cap net | grep -v net_lo_00_00_00_00_00_00` do #echo "forloop test:"$device virsh nodedev-dumpxml $device > device_xml name=`xmlpath_args "device/capability/interface" < device_xml` #echo "test:"$name name="${name// /}" #echo "forloop:name:"$name address=`xmlpath_args "device/capability/address" < device_xml` address="${address// /}" #echo "forloop:address:"$address parent=`xmlpath_args "device/parent" < device_xml` parent="${parent// /}" #echo "parent:"$parent #the following line created variables 'speed' and 'state' eval `xmlpath_args "device/capability/link" < device_xml` #echo "speed:"$speed #echo "state:"$state virsh nodedev-dumpxml $parent > parent_xml driver=`xmlpath_args "device/driver/name" < parent_xml` [ $? -eq 1 ] && driver="N/A" driver="${driver// /}" #echo "driver:"$driver #If the device is not up try to bring it up and reload state if [[ $state == 'down' ]] && ([[ $driver == "igb" ]] ) then   >&2 echo "$name is down. Trying to bring it up"   ifup $name   sleep 2   virsh nodedev-dumpxml $device > device_xml   eval `xmlpath_args "device/capability/link" < device_xml` fi if [[ $state == 'down' ]]  && (  [[ $driver == "igb" ]]  ) then     >&2 echo "Interfaces must be connected and up in order to properly detect the speed. You can provide this information manually or skip the interface"     keep_asking=true     skip_interface=true     unset speed     while $keep_asking; do         read -p "Do you want to skip interface $name ($address) [y/N] " -i "n" skip   case $skip in             [Yy]* ) keep_asking=false;;             * ) skip_interface=false;                 default_speed="10000"                 while $keep_asking; do                    read -p "What is the speed of the interface expressed in Mbps? ($default_speed) " speed;                    [[ -z $speed ]] && speed=$default_speed                    [[ $speed =~ ''|*[!0-9] ]] && echo "The input must be an integer" && continue;                    keep_asking=false ;                 done;;         esac     done    $skip_interface && continue fi #the following line creates a 'node' variable eval `xmlpath_args "device/capability/numa" < parent_xml` # "numa:"$node #the following line creates the variable 'type' #in case the interface is a PF the value is 'virt_functions' #in case the interface is a VF the value is 'phys_function' type="N/A" eval `xmlpath_args "device/capability/capability" < parent_xml` #obtain pci #the following line creates the variables 'domain' 'bus' 'slot' and 'function' #eval `xmlpath_args "device/capability/address" < parent_xml` #pci="${domain#*x}:${bus#*x}:${slot#*x}.${function#*x}" #underscored_pci="${pci//\:/_}" #underscored_pci="pci_${underscored_pci//\./_}" #echo "uderscored_pci:"$underscored_pci #break pci="${parent:4:4}:${parent:9:2}:${parent:12:2}.${parent:15:1}" if ( [[ $driver == "igb" ]] ) then   underscored_pci="pf"$parent   PF_list[${#PF_list[@]}]=$underscored_pci   eval declare -A $underscored_pci   eval $underscored_pci["name"]=$name   eval $underscored_pci["numa"]=$node   eval $underscored_pci["mac"]=$address   eval $underscored_pci["speed"]=$speed   eval $underscored_pci["pci"]=$pci   #request switch port to the user if this information is being provided and include it   if  $prov_conn   then     unset switch_port     read -p "What is the port name in the switch $dpid where port $name ($pci) is connected? (${name}-${PORT_RANDOM}/$iface_counter) " switch_port     [[ -z $switch_port ]] && switch_port="${name}-${PORT_RANDOM}/$iface_counter"     iface_counter=$((iface_counter+1))I     eval $underscored_pci["dpid"]=$dpid     eval $underscored_pci["switch_port"]=$switch_port   fi   #Añado el pci de cada uno de los hijos   SRIOV_counter=0   for child in `xmlpath_args "device/capability/capability/address" < parent_xml`   do     SRIOV_counter=$((SRIOV_counter+1))     #the following line creates the variables 'domain' 'bus' 'slot' and 'function'     eval $child     eval $underscored_pci["SRIOV"$SRIOV_counter]="${domain#*x}_${bus#*x}_${slot#*x}_${function#*x}"     #echo "sriov address:"$underscored_pci["SRIOV"$SRIOV_counter]   done   eval $underscored_pci["SRIOV"]=$SRIOV_counter   #echo "SRIOV_counter:"$SRIOV_counter #Si se trata de un SRIOV (tiene una capability con type 'phys_function') elif [[ $type == 'phys_function' ]] then   #eval `xmlpath_args "device/capability/capability/address" < parent_xml`   #echo "domain:"$domain   #echo "bus:"$bus   #echo "slot:"$slot   #echo "function" $function   #pci="${domain#*x}:${bus#*x}:${slot#*x}.${function#*x}"   #echo "pci:"$pci   #underscored_pci="${pci//\:/_}"   #underscored_pci="pci_${underscored_pci//\./_}"   #echo "uderscored_pci:"$underscored_pci   underscored_pci="vf"$parent   VF_list[${#VF_list[@]}]=$underscored_pci   eval declare -A $underscored_pci   eval $underscored_pci["source_name"]=$name   #echo $underscored_pci["source_name"]   eval $underscored_pci["mac"]=$address   #echo $underscored_pci["mac"]   eval $underscored_pci["pci"]=$pci   #echo $underscored_pci["pci"] fi rm -f device_xml parent_xml done IFS=$OLDIFS echo "#This file was created by $0" echo "#for adding this compute node to openvim" echo "#copy this file to openvim controller and run" echo "#openvim host-add <this>" echo echo "host:" echo "  name:    $HOST_NAME" echo "  user:    $1" echo "  ip_name: $2" echo "host-data:" echo "  name:        $HOST_NAME" echo "  user:        $1" echo "  ip_name:     $2" echo "  ranking:     100" echo "  description: $HOST_NAME" echo "  features:    $FEATURES_LIST" echo "  numas:" numa=0 while [[ $numa -lt $NUMAS ]] do   echo "  - numa_socket:  $numa" #MEMORY   if [ -f /sys/devices/system/node/node${numa}/hugepages/hugepages-1048576kB/nr_hugepages ]   then     echo "    hugepages: " `cat /sys/devices/system/node/node${numa}/hugepages/hugepages-1048576kB/nr_hugepages`   else     #TODO hugepages of 2048kB size     echo "    hugepages:  0"   fi   memory=`head -n1 /sys/devices/system/node/node${numa}/meminfo  | gawk '($5=="kB"){print $4}'`   memory=$((memory+1048576-1))   #memory must be ceiled   memory=$((memory/1048576))   #from `kB to GB   echo "    memory:    $memory" #CORES   echo "    cores:"   FIRST="-" #first item in a list start with "-" in yaml files, then it will set to " "   for cpu in $CPUS   do     PHYSICAL=`echo $cpu | cut -f 1 -d"-"`     CORE=`echo $cpu | cut -f 2 -d"-"`     THREAD=`echo $cpu | cut -f 3 -d"-"`     [[ $PHYSICAL != $numa ]] && continue   #skip non physical     echo "    - core_id:   $CORE"     echo "      thread_id: $THREAD"     #check if eligible     cpu_isolated="no"     for isolcpu in $isolcpus     do       isolcpu_start=`echo $isolcpu | cut -f 1 -d"-"`       isolcpu_end=`echo $isolcpu | cut -f 2 -d"-"`       if [ "$THREAD" -ge "$isolcpu_start" -a "$THREAD" -le "$isolcpu_end" ]       then         cpu_isolated="yes"         break       fi     done     [[ $cpu_isolated == "no" ]] &&   echo "      status:    noteligible"     FIRST=" "   done   #echo "numa:"$numa   #NIC INTERFACES   interfaces_nb=0   #echo ${#PF_list[@]}   for ((i=0; i<${#PF_list[@]};i++))   do     underscored_pci=${PF_list[$i]}     #echo "pci:"$underscored_pci     pname=$(get_hash_value $underscored_pci "name")     #echo "pname:"$pname     #pnuma=$(get_hash_value $underscored_pci "numa")     pnuma=1     #echo "pnuma:"$pnuma     [[ $pnuma != $numa ]] && continue     pmac=$(get_hash_value $underscored_pci "mac")     #echo "pmac:"$pmac     ppci=$(get_hash_value $underscored_pci "pci")     #echo "ppci:"$ppci     pspeed=$(get_hash_value $underscored_pci "speed")     pSRIOV=$(get_hash_value $underscored_pci "SRIOV")     [[ $interfaces_nb -eq 0 ]] && echo "    interfaces:"     interfaces_nb=$((interfaces_nb+1))     sriov_nb=0     echo "    - source_name: $pname"     echo "      Mbps: $pspeed"     echo "      pci: \"$ppci\""     echo "      mac: \"$pmac\""     if $prov_conn       then         pdpid=$(get_hash_value $underscored_pci "dpid")         pswitch_port=$(get_hash_value $underscored_pci "switch_port")         echo "      switch_dpid: $pdpid"         echo "      switch_port: $pswitch_port"     fi     for ((j=1;j<=$pSRIOV;j++))     do       childSRIOV="vfpci_"$(get_hash_value $underscored_pci "SRIOV"$j)       #echo "childSRIOV:"$childSRIOV       pname=$(get_hash_value $childSRIOV "source_name")       index=${pname##*_}       pmac=$(get_hash_value $childSRIOV "mac")       ppci=$(get_hash_value $childSRIOV "pci")       [[ $sriov_nb -eq 0 ]] && echo "      sriovs:"       sriov_nb=$((sriov_nb+1))       echo "      - mac: \"$pmac\""       echo "        pci: \"$ppci\""       echo "        source_name: $index"     done   done   numa=$((numa+1)) done #remove_vf_driver ixgbe remove_vf_driver igb #Bring up all interfaces for ((i=0; i<${#PF_list[@]};i++)) do   underscored_pci=${PF_list[$i]}   pname=$(get_hash_value $underscored_pci "name")   ifup $pname done

相關推薦

獲取支援SRIOV網路介面裝置資訊

1.首先 virsh nodedev-list --cap net | grep -v net_lo_00_00_00_00_00_00 可以檢視當前系統現有的網路裝置 如下圖所示 2.但是上述只能顯示裝置資訊,無法顯示出裝置的pci相關資訊,也可以virsh nod

前端Vue框架(通過axios獲取地址串(介面資訊)

獲取地址串資訊:某些公司會提供一些地址串的介面,可以通過vue框架使用axios獲取裡面的值,並迴圈遍歷參考程式碼:   <!DOCTYPE html> <html> <head> <title>demo5 社群作業1</

Android 獲取手機的IMEI等裝置資訊

獲取IMEI等 public String getPhoneInfo(Context context) { TelephonyManager tm = (TelephonyMa

Android 通過讀取本地Arp表獲取當前區域網內其他裝置資訊

目的:獲取當前區域網內其他連線裝置的IP 和MAC資訊。 步驟: 1. 獲取本機wifi ip資訊; 2. 根據ip 去傳送ARP請求 3. 讀取本地ARP 表;

Linux 下 可以使用ioctl()函式 以及 結構體 struct ifreq 結構體struct ifconf來獲取網路介面的各種資訊

轉載於:windeal專欄   Linux 下 可以使用ioctl()函式 以及 結構體 struct ifreq  結構體struct ifconf來獲取網路介面的各種資訊。   ioctl 首先看ioctl()用法 ioctl()原型如下:

獲取網路介面資訊——ioctl()函式與結構體struct ifreq、 struct ifconf

#include <sys/types.h> #include <sys/ioctl.h> #include <sys/socket.h> #include <net/if.h> #include <stdio.h> #inclu

使用GetIfTable獲取MIB_IFTABLE和MIB_IFROW獲取網路介面資訊

#include <iphlpapi.h> #pragma comment ( lib, "iphlpapi.lib") 使用GetIfTable()獲取各個埠資訊的時候用到的 _MIB_IFTABLE結構: typedef struct _MIB_IFT

Windows下USB磁碟開發系列三:列舉系統中U盤、並獲取裝置資訊

前面我們介紹了列舉系統中的U盤碟符(見《Windows下USB磁碟開發系列一:列舉系統中U盤的碟符》)、以及獲取USB裝置的資訊(見《Windows下USB磁碟開發系列二:列舉系統中所有USB裝置》)。有個時候我們不僅僅需要獲取U盤碟符(路徑),而且需要獲取該U盤的硬體資訊,比如廠商、friendl

React Native獲取裝置資訊元件

轉載 https://www.jianshu.com/p/907b003835dc 本文原創首發於公眾號:ReactNative開發圈,轉載需註明出處。 這次介紹的獲取移動裝置資訊的元件名叫:react-native-device-info,相容IOS和安

從 HTTPServletRequest 中根據 User-Agent 獲取訪問裝置資訊

背景:根據 HttpServletRequest獲取訪問裝置資訊。 Http 協議請求頭中的 User-Agent屬性會將客戶端裝置的資訊傳遞給伺服器,這些資訊包括客戶端作業系統及版本、CPU 型別、瀏覽器及版本、瀏覽器渲染引擎、瀏覽器語言、瀏覽器外掛等。 參考: 使用者代理(U

【迅為iTop4412學習筆記】7.以模組方式註冊裝置,以及驅動獲取裝置資訊

宣告 以下都是我剛開始看驅動視訊的個人強行解讀,如果有誤請指出,共同進步。 本節目標 以module的方式註冊裝置 正文 我們之前提到的流程:註冊裝置->註冊驅動,匹配成功則呼叫probe函式。 (至於probe函式是用來幹啥的

React Native 獲取裝置資訊

一、獲取方案 使用開源的第三方元件react-native-device-info,該元件適用於iOS和Android雙平臺。 二、元件使用 在ReactNative專案中下載第三方元件依賴包, 我們一般都是使用命令列來執行下載:  進入專案執行:npm inst

adb獲取android裝置資訊

import subprocess #ADB執行命令列,包括一些常用命令 class ADBShell: def __init__(self, adb_path=""): self.adb_path = adb_path def invoke(self,cmd):

iOS 獲取裝置資訊,mac地址,IP地址,裝置名稱

#import "DeviceInfoUtil.h" #import "GlobleData.h" #import "sys/utsname.h" #import <AdSupport/AdSupport.h> #import <ifaddrs.h>

iOS開發-Object-C獲取手機裝置資訊(UIDevice)

一、獲取UiDevice裝置資訊 // 獲取裝置名稱 NSString *name = [[UIDevice currentDevice] name]; // 獲取裝置系統名稱 NSString *systemName = [[UIDevice currentDevice] systemName

移動端如何獲取裝置資訊

這次介紹的獲取移動裝置資訊的元件名叫:react-native-device-info,相容IOS和安卓雙平臺,可以獲取裝置ID、裝置品牌、裝置型號、IP以及APP版本號等資訊。是一個應用很廣泛的基礎元件。 親測可用,已在雙端真機上測試,均能獲取到裝置資訊! 安裝 npm install

LTE網路主要介面包含資訊概述

1、簽約資料:包括使用者標識(IMSI、MSISDN等)、簽約業務APN、服務等級Qos、接入限制ARD、使用者位置、漫遊限制等資訊,該類資訊通過S6a介面的位置更新、插入使用者資料等操作進行互動 2、認證資料:包括鑑權引數(Rand、Res、Kasme、AUTN四元組),該類資訊通過S6a介面的鑑權操作進

js 獲取硬體裝置資訊

1、檢測安卓裝置    var userAgent = navigator.userAgent;     var index = userAgent.indexOf("Android")     if(index >= 0){         var androi

根據mac地址+deviceid獲取裝置唯一編碼 獲取手機及SIM卡相關資訊

根據mac地址+deviceid獲取裝置唯一編碼: private static String DEVICEKEY = ""; /** * 根據mac地址+deviceid

獲取Android裝置資訊

在開發的過程中有可能根據需要顯示一些裝置的狀態或系統資訊。下面是收集到的一些資訊 一、獲取當前電量 每當電量改變時系統都會廣播發Intent.ACTION_BATTERY_CHANGED訊息出來,應用程式只需要註冊並建立一個接收器就能獲取當前的電量 建立一個廣播接收器類Ba