Binder机制5--- Binder实现进程管理服务示例

6. 用eclipse实现PMService

PMservice是一个通过Service服务,来实现任务管理的程序。分为客户端PMClient和服务端PMService。

PMService提供一些操作方法:

  • 服务开始的提示方法:getVal();
  • 任务管理器的查询方法:getProcessID() 获取进程号,和getProcessName()获取进程名;
  • 以及终止进程的方法:killProc(String ID),来提供服务给客户端。

PMClient使用PMService所提供的服务,来调用这些方法实现业务逻辑,并提供显示界面。


对于PMService的实现

  1. 通过ActivityManager activityManager = (ActivityManager) getSystemService("activity"); 获得activityService
  2. 编写aidl文件,eclipse会自动生成相应的Stub和Proxy的接口实现

对于PMClient的实现

  1. 复制PMService的aidl文件,eclipse会为PMClient生成相应的接口实现
  2. 通过在ServiceConnection:: onServiceConnected()中,PMService = IPMService.Stub.asInterface(service); 获得PMService创建的 PMServiceProxy(new BinderProxy());  并把这个proxy对象保存在PMService中
  3. 在onCreate()方法中,调用bindService(new Intent(IPMService.class.getName()),serConn, Context.BIND_AUTO_CREATE);

其中, serConn 是ServiceConnection类的实例化,传递的是PMService对象,这里是把当前类的PMService与PMService那边的PMService绑定在一起,这样就实现了两个进程的通信了


实现流程分析

  1. 调用的时候,客户端首先调用bindService(new Intent (IPMService.class.getName(), serConn,Context.BIND_AUTO_CREATE);激活serviceConnection的onServiceConnected方法,在此方法中获取到一个binder,这个binder是系统给我们的一个与远程进行通信的binder,此binder能够查找系统中注册的service,如果没有查找到该Service,那么可认定该service是从其他apk获得的,就创建一个此service的静态代理类Proxy,否则,就把这个service返回,供客户端调用。
  2. 服务端收到这个Intent后,激活PMServiceImpl extends IPMService.Stub的onBind方法,创建一个Binder返回 (return new PMServiceImpl())。之后,这个Binder负责与客户端的Proxy通信。

源码流程:

PMService的源码

在eclipse新建PMServer工程,我用的是android 4.2.2

先列出PMServer工程的文件清单,其中IPMService.java是通过IPMService.aidl自动创建的


下面是各个文件的源码:

IPMService.aidle

[plain] view plain copy
  1. package com.example.pmserver;  
  2.   
  3.   
  4.   
  5.   
  6. interface IPMService  
  7. {  
  8.     double getVal(String val);  
  9.     List<String> getProcessName();  
  10.     List<String> getProcessID();  
  11.     String killProc(String PID);  
  12. }  
把这个文件放入到我们工程的com.example.pmserver包中,系统会自动生成IPMService.java


为了实现进程信息的查询,我们需要CommandHelper.java这个类,通过API执行shell语言的方式来收集我们需要的进程信息。

CommandHelper.java

  1. package com.example.pmserver;  
  2.   
  3. import com.example.pmserver.CommandResult;  
  4.   
  5. import java.io.BufferedReader;  
  6. import java.io.IOException;  
  7. import java.io.InputStreamReader;  
  8.   
  9. /** 
  10.  * 
  11.  *  
  12.  */  
  13. public class CommandHelper {  
  14.   
  15.     //default time out, in millseconds  
  16.     public static int DEFAULT_TIMEOUT;  
  17.     public static final int DEFAULT_INTERVAL = 1000;  
  18.     public static long START;  
  19.   
  20.   
  21.     public static CommandResult exec(String command) throws IOException, InterruptedException {  
  22.         Process process = Runtime.getRuntime().exec(command);  
  23.         CommandResult commandResult = wait(process);  
  24.         if (process != null) {  
  25.             process.destroy();  
  26.         }  
  27.         return commandResult;  
  28.     }  
  29.   
  30.     private static boolean isOverTime() {  
  31.         return System.currentTimeMillis() - START >= DEFAULT_TIMEOUT;  
  32.     }  
  33.   
  34.     private static CommandResult wait(Process process) throws InterruptedException, IOException {  
  35.         BufferedReader errorStreamReader = null;  
  36.         BufferedReader inputStreamReader = null;  
  37.         try {  
  38.             errorStreamReader = new BufferedReader(new InputStreamReader(process.getErrorStream()));  
  39.             inputStreamReader = new BufferedReader(new InputStreamReader(process.getInputStream()));  
  40.   
  41.             //timeout control  
  42.             START = System.currentTimeMillis();  
  43.             boolean isFinished = false;  
  44.   
  45.             for (;;) {  
  46.                 if (isOverTime()) {  
  47.                     CommandResult result = new CommandResult();  
  48.                     result.setExitValue(CommandResult.EXIT_VALUE_TIMEOUT);  
  49.                     result.setOutput("Command process timeout");  
  50.                     return result;  
  51.                 }  
  52.   
  53.                 if (isFinished) {  
  54.                     CommandResult result = new CommandResult();  
  55.                     result.setExitValue(process.waitFor());  
  56.                       
  57.                     //parse error info  
  58.                     if (errorStreamReader.ready()) {  
  59.                         StringBuilder buffer = new StringBuilder();  
  60.                         String line;  
  61.                         while ((line = errorStreamReader.readLine()) != null) {  
  62.                             buffer.append(line);  
  63.                         }  
  64.                         result.setError(buffer.toString());  
  65.                     }  
  66.   
  67.                     //parse info  
  68.                     if (inputStreamReader.ready()) {  
  69.                         StringBuilder buffer = new StringBuilder();  
  70.                         String line;  
  71.                         while ((line = inputStreamReader.readLine()) != null) {  
  72.                             buffer.append(line);  
  73.                         }  
  74.                         result.setOutput(buffer.toString());  
  75.                     }  
  76.                     return result;  
  77.                 }  
  78.   
  79.                 try {  
  80.                     isFinished = true;  
  81.                     process.exitValue();  
  82.                 } catch (IllegalThreadStateException e) {  
  83.                     // process hasn't finished yet  
  84.                     isFinished = false;  
  85.                     Thread.sleep(DEFAULT_INTERVAL);  
  86.                 }  
  87.             }  
  88.   
  89.         } finally {  
  90.             if (errorStreamReader != null) {  
  91.                 try {  
  92.                     errorStreamReader.close();  
  93.                 } catch (IOException e) {  
  94.                 }  
  95.             }  
  96.   
  97.             if (inputStreamReader != null) {  
  98.                 try {  
  99.                     inputStreamReader.close();  
  100.                 } catch (IOException e) {  
  101.                 }  
  102.             }  
  103.         }  
  104.     }  
  105. }  

下面,需要提供一些操作的接口,以便调用

CommandResult.java

  1. package com.example.pmserver;  
  2.   
  3. public class CommandResult {  
  4.     public static final int EXIT_VALUE_TIMEOUT=-1;  
  5.       
  6.     private String output;  
  7.   
  8.     void setOutput(String error) {  
  9.         output=error;  
  10.     }  
  11.   
  12.     String getOutput(){  
  13.         return output;  
  14.     }  
  15.   
  16.     int exitValue;  
  17.   
  18.     void setExitValue(int value) {  
  19.         exitValue=value;  
  20.     }  
  21.   
  22.     int getExitValue(){  
  23.         return exitValue;  
  24.     }  
  25.   
  26.     private String error;  
  27.   
  28.     /** 
  29.      * @return the error 
  30.      */  
  31.     public String getError() {  
  32.         return error;  
  33.     }  
  34.   
  35.     /** 
  36.      * @param error the error to set 
  37.      */  
  38.     public void setError(String error) {  
  39.         this.error = error;  
  40.     }  
  41. }  

接下来,就是我们Service的核心文件了,实现了业务逻辑。

PMService.java

  1. package com.example.pmserver;  
  2.   
  3. import java.io.IOException;  
  4. import java.util.ArrayList;  
  5. import java.util.Iterator;  
  6. import java.util.List;  
  7. import com.example.pmserver.CommandHelper;  
  8. import com.example.pmserver.CommandResult;  
  9. import android.os.IBinder;  
  10. import android.os.RemoteException;  
  11. import android.app.ActivityManager;  
  12. import android.app.ActivityManager.RunningAppProcessInfo;  
  13. import android.app.Service;  
  14. import android.content.Intent;  
  15. import android.util.Log;  
  16.   
  17. public class PMService extends Service {  
  18.   
  19.      private static final String TAG = "PMService";   
  20.        
  21.      List<String> ProcName = new ArrayList<String>();  
  22.      List<String> ProcID = new ArrayList<String>();  
  23.   
  24.         public class PMServiceImpl extends IPMService.Stub {    
  25.   
  26.             @Override    
  27.             public double getVal(String val) throws RemoteException {              
  28.                 Log.v(TAG, "getVal() called for " + val);    
  29.                 return 1.0;  //test the binder transaction is ok between c/s  
  30.             }          
  31.                           
  32.             public List<String> getProcessName() {  
  33.                   
  34.                 List<RunningAppProcessInfo> procList = this.getProcessInfo(); //get process info  
  35.                 int j = 0;  
  36.                 Iterator<RunningAppProcessInfo> iterator = procList.iterator();  
  37.                   
  38.                 if(iterator.hasNext()) {  
  39.                     do {  
  40.                         RunningAppProcessInfo procInfo = iterator.next();   
  41.               
  42.                         Log.v("ProcInfo""ProcName = " + procInfo.processName);  
  43.                           
  44.                         ProcName.add(procInfo.processName);                       
  45.                         //ProcID.add(Integer.toString(procInfo.pid));  
  46.                           
  47.                         Log.v("ProcName""ProcName = " + ProcName.get(j++));  
  48.                           
  49.                     }while(iterator.hasNext());  
  50.                 }  
  51.   
  52.                 return ProcName;  
  53.             }  
  54.               
  55.             public List<String> getProcessID() {  
  56.                   
  57.                 List<RunningAppProcessInfo> procList = this.getProcessInfo();  
  58.                 int i = 0;                
  59.                 Iterator<RunningAppProcessInfo> iterator = procList.iterator();  
  60.               
  61.                 if(iterator.hasNext()) {  
  62.                     do {  
  63.                         RunningAppProcessInfo procInfo = iterator.next();   
  64.   
  65.                         Log.v("ProcInfo","ProcID = " + procInfo.pid);  
  66.   
  67.                         ProcID.add(String.valueOf(procInfo.pid));  
  68.                         //ProcID.add(Integer.toString(procInfo.pid));  
  69.                           
  70.                         Log.v("ProcName""ProcID = " + ProcID.get(i++));  
  71.                           
  72.                     }while(iterator.hasNext());  
  73.                 }  
  74.          
  75.                 return ProcID;  
  76.             }  
  77.               
  78.             @Override  
  79.             public String killProc(String PID) throws RemoteException {  
  80.                 // TODO Auto-generated method stub  
  81.                 String cmd = "kill -9 "+PID;  
  82.                 String reply = "";  
  83.                   
  84.                 Log.v("cmd",cmd);  
  85.                 try {  
  86.                       
  87.                     CommandHelper.DEFAULT_TIMEOUT = 5000;  
  88.                     CommandResult result = CommandHelper.exec(cmd);  
  89.                     if (result != null) {  
  90.                         if(result.getError()!=null)  
  91.                         {  
  92.                             Log.v("Output","Error:" + result.getError());  
  93.                             reply = result.getError();  
  94.                         }  
  95.                         if(result.getOutput()!=null)  
  96.                         {  
  97.                             Log.v("Output","Output:" + result.getOutput());       
  98.                             reply = result.getOutput();  
  99.                         }  
  100.                     }  
  101.                       
  102.                 } catch (IOException ex) {  
  103.                     Log.v("Output","IOException:" + ex.getLocalizedMessage());  
  104.                 } catch (InterruptedException ex) {  
  105.                     Log.v("Output","InterruptedException:" + ex.getLocalizedMessage());  
  106.                 }  
  107.                 return reply;  
  108.                   
  109.                   
  110.             }  
  111.               
  112.             public  void exec(String command) throws IOException, InterruptedException {  
  113.                 // Process process = Runtime.getRuntime().exec(command);  
  114.                 Runtime.getRuntime().exec(command);           
  115.                  return ;  
  116.              }  
  117.           
  118.             public List<RunningAppProcessInfo> getProcessInfo() {  
  119.                 List<RunningAppProcessInfo> procList = new ArrayList<RunningAppProcessInfo>();  
  120.                   
  121.                // ActivityManager activityManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);  
  122.                 ActivityManager activityManager = (ActivityManager) getSystemService("activity");  
  123.                 procList = activityManager.getRunningAppProcesses();  
  124.              
  125.                 return procList;  
  126.             }  
  127.         }    
  128.           
  129.         @Override    
  130.         public void onCreate() {    
  131.             super.onCreate();    
  132.             Log.v(TAG, "onCreate called");    
  133.         }    
  134.         
  135.         @Override    
  136.         public void onDestroy() {    
  137.             super.onDestroy();    
  138.             Log.v(TAG, "onDestory() called");    
  139.         }    
  140.         
  141.         @Override    
  142.         public void onStart(Intent intent, int startId) {    
  143.             super.onStart(intent, startId);    
  144.             Log.v(TAG, "onStart() called");    
  145.         }    
  146.         
  147.         @Override    
  148.         public IBinder onBind(Intent intent) {    
  149.             Log.v(TAG, "onBind() called");    
  150.             return new PMServiceImpl();    
  151.         }    
  152.   
  153. }  

AndroidManifest.xml配置文件

  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     package="com.example.pmserver"  
  4.     android:versionCode="1"  
  5.     android:versionName="1.0" >  
  6.   
  7.     <uses-sdk  
  8.         android:minSdkVersion="8"  
  9.         android:targetSdkVersion="17" />  
  10.   
  11.     <application  
  12.         android:allowBackup="true"  
  13.         android:icon="@drawable/ic_launcher"  
  14.         android:label="@string/app_name"  
  15.         android:theme="@style/AppTheme" >  
  16.         <service  
  17.             android:name="com.example.pmserver.PMService"  
  18.             android:label="@string/app_name" >  
  19.             <intent-filter>  
  20.                 <action android:name="com.example.pmserver.IPMService" />  
  21.             </intent-filter>  
  22.         </service>  
  23.     </application>  
  24.   
  25. </manifest>  

Service这边不需要显示操作,界面的配置就不需要了。这样,Service这边就OK了。


PMClient的源码

这个是PMClient工程的文件清单,


IPMService.aidl直接从PMService中拷贝过来就好,这里就不列出了。同样,会自动生成IPMService.java

CommandHelper.java和CommandResult.java这里不需要(这里,我只是做测试之用),不需要添加,在com.example.pmclient中,只需添加PMClientActivity.java即可。

PMClientActivity.java

  1. package com.example.pmclient;  
  2.   
  3. import com.example.pmserver.IPMService;  
  4. import com.example.pmclient.CommandHelper;  
  5. import com.example.pmclient.CommandResult;  
  6.   
  7. import java.io.IOException;  
  8. import java.util.ArrayList;  
  9. import java.util.HashMap;  
  10. import java.util.List;  
  11. import java.util.Map;  
  12. import android.os.Bundle;  
  13. import android.os.IBinder;   
  14. import android.app.Activity;  
  15. import android.view.View;  
  16. import android.widget.AdapterView;  
  17. import android.widget.ListView;  
  18. import android.widget.SimpleAdapter;  
  19. import android.content.ComponentName;    
  20. import android.content.Context;    
  21. import android.content.Intent;    
  22. import android.content.ServiceConnection;    
  23. import android.os.RemoteException;    
  24. import android.util.Log;    
  25. import android.widget.Toast;  
  26. import android.widget.AdapterView.OnItemClickListener;  
  27.   
  28. public class PMClientActivity extends Activity {  
  29.   
  30.         protected static final String TAG = "TestaidlClient";    
  31.         private IPMService PMService = null;    
  32.   
  33.         @Override    
  34.         public void onCreate(Bundle savedInstanceState) {    
  35.             super.onCreate(savedInstanceState);    
  36.             
  37.             setContentView(R.layout.list_main);     
  38.             bindService(new Intent(IPMService.class.getName()),serConn, Context.BIND_AUTO_CREATE);            
  39.         }    
  40.           
  41.         public void onDestroy(){  
  42.             super.onDestroy();    
  43.             Log.v(TAG, "onDestory() called");    
  44.             unbindService(serConn);    
  45.         }  
  46.         
  47.         private void callService() {    
  48.             try {    
  49.                 double val = PMService.getVal("Liang");    
  50.                 if(val == 1.0)  {  
  51.                     Toast.makeText(this"Service is ready!",    
  52.                         Toast.LENGTH_LONG).show();    
  53.                 }  
  54.                 setNameID(PMService.getProcessID(), PMService.getProcessName());  
  55.                   
  56.             } catch (RemoteException e) {    
  57.                 Log.e("MainActivity", e.getMessage(), e);    
  58.             }    
  59.         }    
  60.         
  61.         private ServiceConnection serConn = new ServiceConnection() {    
  62.             // 此方法在系统建立服务连接时调用    
  63.             @Override    
  64.             public void onServiceConnected(ComponentName name, IBinder service) {    
  65.                 Log.v(TAG, "onServiceConnected() called");    
  66.                 PMService = IPMService.Stub.asInterface(service);    
  67.                 callService();    
  68.             }    
  69.         
  70.             // 此方法在销毁服务连接时调用    
  71.             @Override    
  72.             public void onServiceDisconnected(ComponentName name) {    
  73.                 Log.v(TAG, "onServiceDisconnected()");    
  74.                 PMService = null;    
  75.             }    
  76.         };    
  77.           
  78.           
  79.         public void setNameID(final List<String> ProcID, final List<String> ProcName) {           
  80.             //绑定Layout里面的ListView    
  81.             ListView list = (ListView) findViewById(R.id.ListView01);   
  82.               
  83.             //每个list里面放的都是MAP,map里面放的是键值对  
  84.             ArrayList<Map<String, String>> Items = new ArrayList<Map<String, String>>();  
  85.               
  86.             //把该显示的内容放到list中  
  87.             for (int i = 0; i < ProcID.size(); i++)  
  88.             {  
  89.                 Map<String, String> item = new HashMap<String, String>();  
  90.                 String PIDbuf = "PID: "+ProcID.get(i);  
  91.                 item.put("ProcID", PIDbuf);  
  92.                 String PNamebuf = "PName: "+ProcName.get(i);  
  93.                 item.put("ProcName", PNamebuf);  
  94.                 Items.add(item);  
  95.             }  
  96.               
  97.             //构建适配器Adapter,将数据与显示数据的布局页面绑定  
  98.             final SimpleAdapter simpleAdapter = new SimpleAdapter(this, Items,  
  99.             R.layout.list_proc_info, new String[]{ "ProcID""ProcName" },  
  100.             new int[]{ R.id.ProcID,  R.id.ProcName});  
  101.               
  102.             //通过setAdapter()方法把适配器设置给ListView  
  103.             list.setAdapter(simpleAdapter);  
  104.               
  105.             list.setOnItemClickListener(new OnItemClickListener() {                   
  106.                 @Override  
  107.                 public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,  
  108.                         long arg3) {  
  109.                     // TODO Auto-generated method stub    
  110.                     String result = "";  
  111.                       
  112.                     Log.v("ClickInfo""arg0 = " + arg0 + "arg1 = " + arg1 + " arg2 = " + arg2 +" arg3 = " + arg3);  
  113.                       
  114.                     //arg2 放的是process的name        
  115.                     try {  
  116.                         result = PMService.killProc(ProcID.get(arg2));  
  117.                     } catch (RemoteException e) {  
  118.                         // TODO Auto-generated catch block  
  119.                         e.printStackTrace();  
  120.                     }  
  121.                     if(result == null)  
  122.                     {  
  123.                         result = "success!";  
  124.                     }  
  125.                       
  126.                     ToastMSG(result);  
  127.                       
  128.                     //刷新页面  
  129.                     simpleAdapter.notifyDataSetChanged();     
  130.                 }    
  131.             });    
  132.               
  133.                   
  134.         }  
  135.           
  136.         public void ToastMSG(String info)  
  137.         {  
  138.             Toast.makeText(this"Info: " + info,    
  139.                     Toast.LENGTH_LONG).show();            
  140.         }  
  141.                       
  142. }  

再来看布局的设置,一共有2个布局文件,在res/layout/中:

list_main.xml

  1. <?xml version="1.0" encoding="utf-8"?>    
  2. <LinearLayout     
  3.     android:id="@+id/LinearLayout01"     
  4.     android:layout_width="fill_parent"     
  5.     android:layout_height="fill_parent"     
  6.     xmlns:android="http://schemas.android.com/apk/res/android">    
  7. <ListView android:layout_width="wrap_content"     
  8.           android:layout_height="wrap_content"     
  9.           android:id="@+id/ListView01"    
  10.           android:background="#A9A9A9"/>  
  11. </LinearLayout>  

list_proc_info.xml

  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <!--   <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.          android:orientation="horizontal"  
  4.          android:layout_width="fill_parent"  
  5.          android:layout_height="wrap_content">  
  6.           <TextView android:id="@+id/ProcID"  
  7.              android:layout_width="wrap_content"  
  8.              android:layout_height="fill_parent"  
  9.              android:textSize="16dp"  
  10.              android:gravity="center_vertical"  
  11.              android:paddingLeft="10dp" />  
  12.         
  13.          <TextView android:id="@+id/ProcName"  
  14.              android:layout_width="wrap_content"  
  15.              android:layout_height="fill_parent"  
  16.              android:textSize="16dp"  
  17.              android:gravity="center_vertical"  
  18.              android:paddingLeft="10dp" />  
  19.         
  20.      </LinearLayout>  
  21. -->         
  22.     <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  23.         android:orientation="horizontal"  
  24.         android:layout_width="fill_parent"  
  25.         android:layout_height="fill_parent"  
  26.         >  
  27.    
  28.    
  29.     <ImageView android:id="@+id/Procimg"  
  30.         android:layout_width="wrap_content"  
  31.         android:layout_height="wrap_content"  
  32.         android:layout_margin="5px"  
  33.         android:src="@drawable/ic_launcher"/>  
  34.    
  35.     <LinearLayout android:orientation="vertical"  
  36.         android:layout_width="wrap_content"  
  37.         android:layout_height="wrap_content">  
  38.    
  39.         <TextView android:id="@+id/ProcID"  
  40.             android:layout_width="wrap_content"  
  41.             android:layout_height="wrap_content"  
  42.             android:textColor="#FFFFFFFF"  
  43.             android:textSize="40px" />  
  44.         <TextView android:id="@+id/ProcName"  
  45.             android:layout_width="wrap_content"  
  46.             android:layout_height="wrap_content"  
  47.             android:textColor="#FFFFFFFF"  
  48.             android:textSize="30px" />  
  49.    
  50.     </LinearLayout>  
  51.    
  52.    
  53. </LinearLayout>  

最后,是配置文件:

AndroidManifest.xml

  1. <?xml version="1.0" encoding="utf-8"?>  
  2.   
  3. <manifest xmlns:android="http://schemas.android.com/apk/res/android"  
  4.       
  5.     package="com.example.pmclient"  
  6.     android:versionCode="1"  
  7.     android:versionName="1.0" >  
  8.   
  9.     <uses-sdk  
  10.         android:minSdkVersion="8"  
  11.         android:targetSdkVersion="17"  
  12.         android:sharedUserId="android.uid.system" />  
  13.   
  14.     <application  
  15.         android:allowBackup="true"  
  16.         android:icon="@drawable/ic_launcher"  
  17.         android:label="@string/app_name"  
  18.         android:theme="@style/AppTheme" >  
  19.         <activity  
  20.             android:name="com.example.pmclient.PMClientActivity"  
  21.             android:label="@string/app_name" >  
  22.             <intent-filter>  
  23.                 <action android:name="android.intent.action.MAIN" />  
  24.   
  25.                 <category android:name="android.intent.category.LAUNCHER" />  
  26.             </intent-filter>  
  27.         </activity>  
  28.     </application>  
  29.   
  30. </manifest>  

关于布局文件的字段名(@XXX),这里没有给出对应的配置文件,因为太简单了!请大家自行设置。


大功告成了!上效果图!




界面比较简单,单击对应的进程即可杀掉进程。这里由于Service的权限不够,导致进程不能结束。另外,杀掉进程后(可以尝试杀掉PMService自己,界面会自刷新)。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值