当前位置:首页 > 开发 > 移动开发 > 正文

android 添加系统服务

发表于: 2013-07-26   作者:A_L_85   来源:转载   浏览次数:
摘要: android 添加系统服务 在android系统中, 许许多的系统服务都是在系统启动时加载启动的, 如: PowerManager, WifiManager, InputMethodManager, 等等;   注: 本文参考自RK所提供的一部份补丁, 若涉及侵权, 请及时与我联系.   本文主要用于记录如何添加一个(Pppoe拨号)系统服务:  

android 添加系统服务

在android系统中, 许许多的系统服务都是在系统启动时加载启动的,

如: PowerManager, WifiManager, InputMethodManager, 等等;

 

注: 本文参考自RK所提供的一部份补丁, 若涉及侵权, 请及时与我联系.

 

本文主要用于记录如何添加一个(Pppoe拨号)系统服务:

 

1. 添加IXManager.aidl(AIDL)文件:

 

frameworks/base/pppoe/java/android/net/pppoe/IPppoeManager.aidl

package android.net.pppoe;
interface IPppoeManager
{
    int getPppoeState();
    boolean setupPppoe(String user, String iface, String dns1, String dns2, String password);
    boolean startPppoe();
    boolean stopPppoe();
    String getPppoePhyIface();
}

 frameworks/base/Android.mk中添加编译文件:

 

LOCAL_SRC_FILES += \
	core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl \
	core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl \
	core/java/android/accounts/IAccountManager.aidl \
	core/java/android/accounts/IAccountManagerResponse.aidl \
	core/java/android/accounts/IAccountAuthenticator.aidl \
	core/java/android/accounts/IAccountAuthenticatorResponse.aidl \
	core/java/android/app/IActivityController.aidl \
	core/java/android/app/IActivityPendingResult.aidl \
	core/java/android/app/IAlarmManager.aidl \
	core/java/android/app/IBackupAgent.aidl \
	core/java/android/app/IInstrumentationWatcher.aidl \
	core/java/android/app/INotificationManager.aidl \
	core/java/android/app/IProcessObserver.aidl \
	core/java/android/app/ISearchManager.aidl \
	core/java/android/app/ISearchManagerCallback.aidl \
	core/java/android/app/IServiceConnection.aidl \
	location/java/android/location/ILocationManager.aidl \
	pppoe/java/android/net/pppoe/IPppoeManager.aidl

 添加XManager.java

frameworks/base/pppoe/java/android/net/pppoe/PppoeManager.java
/*  
 *  Copyright(C), 2009-2010, Fuzhou Rockchip Co. ,Ltd.  All Rights Reserved.
 *
 *  File:   PppoeManager.java
 *  Desc:   
 *  Usage:
 *  Note:
 *  Author: cz@rock-chips.com
 *  Version:
 *          v1.0
 *  Log:
    ----Thu Sep 8 2011            v1.0
 */
package android.net.pppoe;

import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.net.DhcpInfo;
import android.os.Binder;
import android.os.IBinder;
import android.os.Handler;
import android.os.Message;
import android.os.Looper;
import android.os.HandlerThread;
import android.os.RemoteException;
import android.util.Log;

import java.util.List;

public class PppoeManager {
    private static final String TAG = "PppoeManager";
    public static final boolean DEBUG = true;
    private static void LOG(String msg) {
        if ( DEBUG ) {
            Log.d(TAG, msg);
        }
    }
    
    /**
     *  Broadcast intent action 
     *      indicating that PPPOE has been enabled, disabled, enabling, disabling, or unknown. 
     *  One extra provides current state as an int.
     *  Another extra provides the previous state, if available.
     * 
     * @see #EXTRA_PPPOE_STATE
     * @see #EXTRA_PREVIOUS_PPPOE_STATE
     */
    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    public static final String PPPOE_STATE_CHANGED_ACTION 
        = "android.net.pppoe.PPPOE_STATE_CHANGED";
    /**
     *  Retrieve it with {@link android.content.Intent#getIntExtra(String,int)}.
     * 
     * @see #PPPOE_STATE_DISABLED
     * @see #PPPOE_STATE_DISABLING
     * @see #PPPOE_STATE_INIT_ENABLED
     * @see #PPPOE_STATE_ENABLING
     * @see #PPPOE_STATE_UNKNOWN
     */
    public static final String EXTRA_PPPOE_STATE = "pppoe_state";
    /**
     * The previous PPPOE state.
     * 
     * @see #EXTRA_PPPOE_STATE
     */
    public static final String EXTRA_PREVIOUS_PPPOE_STATE = "previous_pppoe_state";

    public static final int PPPOE_STATE_CONNECTING = 0;
    public static final int PPPOE_STATE_CONNECTED = 1;
    public static final int PPPOE_STATE_DISCONNECTING = 2;
    public static final int PPPOE_STATE_DISCONNECTED = 3;
    public static final int PPPOE_STATE_UNKNOWN = 4;

    IPppoeManager mService;

    Handler mHandler;
    private PppoeHandler mPppoeHandler;
/**
另一种做法:
    static public IXManager getService()
    {
        if (sService != null) {
            return sService;
        }
        IBinder b = ServiceManager.getService(name);
        sService = IXManager.Stub.asInterface(b);
        return sService;
    }
**/
    public PppoeManager(IPppoeManager service, Handler handler) {
        mService = service;
        mHandler = handler;

        if ( null == mPppoeHandler ) {
            LOG("PppoeManager() : start 'pppoe handle thread'.");
            HandlerThread handleThread = new HandlerThread("Pppoe Handler Thread");
            handleThread.start();
            mPppoeHandler = new PppoeHandler(handleThread.getLooper()/*, this*/);
        }
    }

    private class PppoeHandler extends Handler {
        private static final int COMMAND_START_PPPOE = 1;
        private static final int COMMAND_STOP_PPPOE = 2;

        private Handler mTarget;
        
        public PppoeHandler(Looper looper) {
            super(looper);
        }

        public void handleMessage(Message msg) {       
            
            int event;
            LOG("PppoeHandler::handleMessage() : Entered : msg = " + msg);

            switch (msg.what) {
                case COMMAND_START_PPPOE:
                    try {
                        mService.startPppoe();
                    } catch (RemoteException e) {
                        Log.e(TAG, "startPppoe failed");
                    }
                    break;
                case COMMAND_STOP_PPPOE:
                    try {
                        mService.stopPppoe();
                    } catch (RemoteException e) {
                        Log.e(TAG, "stopPppoe failed");
                    }
                    break;
                default:
                    break;
            }
        }
    }

    public int getPppoeState() {
        try {
            return mService.getPppoeState();
        } catch (RemoteException e) {
            Log.e(TAG, "stopPppoe failed");
            return -1;
        }
    }

    public boolean startPppoe() {
        return mPppoeHandler.sendEmptyMessage(PppoeHandler.COMMAND_START_PPPOE);
    }

    public boolean stopPppoe() {
        return mPppoeHandler.sendEmptyMessage(PppoeHandler.COMMAND_STOP_PPPOE);
    }

    public boolean setupPppoe(String user, String iface, String dns1, String dns2, String password) {
        try {
            return mService.setupPppoe(user, iface, dns1, dns2, password);
        } catch (RemoteException e) {
            return false;
        }
    }

    public String getPppoePhyIface() {
        try {
            return mService.getPppoePhyIface();
        } catch (RemoteException e) {
            return null;
        }
    }
}

 再去看看真正干活的地方:XManagerService.java 也可用XService.java

frameworks/base/services/java/com/android/server/PppoeService.java
/*$_FOR_ROCKCHIP_RBOX_$*/
//$_rbox_$_modify_$_chenzhi_20120309: add for pppoe
/*  
 *  Copyright(C), 2009-2010, Fuzhou Rockchip Co. ,Ltd.  All Rights Reserved.
 *
 *  File:   PppoeService.java
 *  Desc:   
 *  Usage:        
 *  Note:
 *  Author: cz@rock-chips.com
 *  Version:
 *          v1.0
 *  Log:
    ----Thu Sep 8 2011            v1.0
 */

package com.android.server;

import android.app.AlarmManager;
import android.app.PendingIntent;

import android.content.BroadcastReceiver;

import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.net.pppoe.IPppoeManager;
import android.net.pppoe.PppoeManager;
import android.net.NetworkStateTracker;
import android.net.DhcpInfo;
import android.net.NetworkInfo;
import android.net.NetworkInfo.DetailedState;
import android.os.Binder;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.PowerManager;
import android.os.Process;
import android.os.RemoteException;
import android.os.UEventObserver;
import android.provider.Settings;
import android.util.Log;
import android.text.TextUtils;

import java.util.ArrayList;
import java.util.BitSet;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
import java.io.FileDescriptor;
import java.io.PrintWriter;

public class PppoeService extends IPppoeManager.Stub {
    private static final String TAG = "PppoeService";
    private static final boolean DEBUG = true;
    private static void LOG(String msg) {
        if ( DEBUG ) {
            Log.d(TAG, msg);
        }
    }

    private Context mContext;
    private PppoeObserver mObserver;
    private NetworkInfo mNetworkInfo;
    int mPppoeState = PppoeManager.PPPOE_STATE_DISCONNECTED;
    private String mIface;
    
    /*-------------------------------------------------------*/

    PppoeService(Context context) {
        LOG("PppoeService() : Entered.");
       
        mContext = context;
        mObserver = new PppoeObserver(mContext);
    }

    public int getPppoeState() {
        return mPppoeState;
    }
    
    private void setPppoeStateAndSendBroadcast(int newState) {
        int preState = mPppoeState;
        mPppoeState = newState;
        
        final Intent intent = new Intent(PppoeManager.PPPOE_STATE_CHANGED_ACTION);
        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);     
        intent.putExtra(PppoeManager.EXTRA_PPPOE_STATE, newState);
        intent.putExtra(PppoeManager.EXTRA_PREVIOUS_PPPOE_STATE, preState);
        LOG("setPppoeStateAndSendBroadcast() : preState = " + preState +", curState = " + newState);
        mContext.sendStickyBroadcast(intent);
    }
    
    public boolean startPppoe() {
        LOG("startPppoe");
        setPppoeStateAndSendBroadcast(PppoeManager.PPPOE_STATE_CONNECTING);
        if ( 0 != startPppoeNative() ) {
            LOG("startPppoe() : fail to start pppoe!");
            setPppoeStateAndSendBroadcast(PppoeManager.PPPOE_STATE_DISCONNECTED);
            return false;
        } else {
            setPppoeStateAndSendBroadcast(PppoeManager.PPPOE_STATE_CONNECTED);
            return true;
        }
    }
    
    public boolean stopPppoe() {
        setPppoeStateAndSendBroadcast(PppoeManager.PPPOE_STATE_DISCONNECTING);    
        if ( 0 != stopPppoeNative() ) {
            LOG("stopPppoe() : fail to stop pppoe!");
            return false;
        } else {
            setPppoeStateAndSendBroadcast(PppoeManager.PPPOE_STATE_DISCONNECTED);
            return true;
        }
    }
    
    public boolean setupPppoe(String user, String iface, String dns1, String dns2, String password) {
        int ret;
        
        LOG("setupPppoe: ");
        LOG("user="+user);
        LOG("iface="+iface);
        LOG("dns1="+dns1);
        LOG("dns2="+dns2);
//        LOG("password="+password);

        mIface = iface;

        if (0 == setupPppoeNative(user, iface, dns1, dns2, password)) {
            return true;
        } else {
            return false;
        }
    }

    public String getPppoePhyIface() {
        return mIface;	
    }
    	
    private class PppoeObserver extends UEventObserver {
        private static final String PPPOE_UEVENT_MATCH = "SUBSYSTEM=net";
        
        private Context mContext;
        
        public PppoeObserver(Context context) {
            mContext = context;
            LOG("PppoeObserver() : to start observing, to catch uevent with '" + PPPOE_UEVENT_MATCH + "'.");
            startObserving(PPPOE_UEVENT_MATCH);
            init();
        }

        private synchronized final void init() {
        }

        @Override
        public void onUEvent(PppoeObserver.UEvent event) {
            LOG("onUEvent() : get uevent : '" + event + "'.");

            String netInterface = event.get("INTERFACE");
            String action = event.get("ACTION");            
            if ( null != netInterface && netInterface.equals("ppp0") ) {
                if ( action.equals("add") ) {
                    LOG("onUEvent() : pppoe started");
//                    setEthernetEnabled(true);
                }
                else if ( action.equals("remove") ) {
                    LOG("onUEvent() : pppoe stopped");
//                    setEthernetEnabled(false);
                }
           }
        }
    }
/**

以下为JNI调用,在后面,会将这部分实现的步骤附上.

**/
    public native static int setupPppoeNative(String user, String iface,String dns1, String dns2, String password);
    public native static int startPppoeNative();
    public native static int stopPppoeNative();
    public native static int isPppoeUpNative();
}

 涉及JNI部分:

frameworks/base/core/jni/Android.mk
同样,先增加源码文件,
LOCAL_SRC_FILES:= \
	AndroidRuntime.cpp \
    android_animation_PropertyValuesHolder.cpp \
    android_net_pppoe_PppoeNative.cpp

 

添加CPP源文件:

frameworks/base/core/jni/android_net_pppoe_PppoeNative.cpp

//$_rbox_$_modify_$_chenzhi_20120309: add for pppoe

#define LOG_TAG "android_pppoe_PppoeNative.cpp"

#include "jni.h"
#include <utils/misc.h>
#include <android_runtime/AndroidRuntime.h>
#include <utils/Log.h>
#include <cutils/properties.h>

namespace android {
static jint setupPppoeNative(JNIEnv* env, 
                                    jobject clazz, 
                                    jstring user, 
                                    jstring iface, 
                                    jstring dns1, 
                                    jstring dns2, 
                                    jstring password)
{
    int attempt;
    int err = 0;
    char* cmd = (char*)malloc(128);
    char* prop = (char*)malloc(PROPERTY_VALUE_MAX);
    
   ///LOGD("%s", __FUNCTION__);
    
    char *c_user = (char *)env->GetStringUTFChars(user, NULL);
    char *c_iface = (char *)env->GetStringUTFChars(iface, NULL);
    char *c_dns1 = (char *)env->GetStringUTFChars(dns1, NULL);
    char *c_dns2 = (char *)env->GetStringUTFChars(dns2, NULL);
    char *c_password = (char *)env->GetStringUTFChars(password, NULL);

    if (!strcmp(c_dns1, "")) {
        strcpy(c_dns1, "server");
    }
    
    sprintf(cmd, "pppoe_setup:%s %s no %s %s %s NONE", 
            c_user, c_iface, c_dns1, c_dns2, c_password);

    //LOGD("setprop ctl.start %s", cmd);

    if (property_set("ctl.start", cmd) < 0) {
        //LOGE("Failed to start pppoe_setup");
        err = -1;
        goto end;
    }

    for (attempt = 50; attempt > 0;  attempt--) {
        property_get("net.pppoe.status", prop, "");
        if (!strcmp(prop, "setuped")) {
            break;
        }
        usleep(100000);  // 100 ms retry delay
    }
    
    if (attempt == 0) {
        //LOGE("%s: Timeout waiting for pppoe-setup", __FUNCTION__);
        err = -1;
        goto end;
    }
    err = 0;
end:
    free(cmd);
    free (prop);
    return err;
}

static jint startPppoeNative(JNIEnv* env, jobject clazz)
{
        int attempt;
        int err = 0;
        char* prop = (char *)malloc(PROPERTY_VALUE_MAX);
        
        //LOGD("%s", __FUNCTION__);
    
        if (property_set("ctl.start", "pppoe_start") < 0) {
            //LOGE("Failed to start pppoe_start");
            err = -1;
            goto end;
        }
        
        for (attempt = 300; attempt > 0;  attempt--) {
            property_get("net.pppoe.status", prop, "");
            if (!strcmp(prop, "connected")) {
                break;
            }
            usleep(100000);  // 100 ms retry delay
        }
        if (attempt == 0) {
            //LOGE("%s: Timeout waiting for pppoe-start", __FUNCTION__);
            err = -1;
            goto end;
        }
        err = 0;
end:
    free(prop);
    return err;
}

static jint stopPppoeNative(JNIEnv* env, jobject clazz)
{
    int attempt;
    int err = 0;
    char* prop = (char *)malloc(PROPERTY_VALUE_MAX);
    
    //LOGD("%s", __FUNCTION__);
    
    if (property_set("ctl.start", "pppoe_stop") < 0) {
        //LOGE("Failed to start pppoe_stop");
        err = -1;
        goto end;
    }
    
    for (attempt = 100; attempt > 0;  attempt--) {
        property_get("net.pppoe.status", prop, "");
        if (!strcmp(prop, "disconnected")) {
            property_set("ctl.stop", "pppoe_stop");
            err = 0;
            goto end;
        }
        usleep(100000);  // 100 ms retry delay
    }
    property_set("ctl.stop", "pppoe_stop");
    err = -1;
end:
    free(prop);
    return err;
}

static jint isPppoeUpNative(JNIEnv* env, jobject clazz)
{
    //LOGD("%s", __FUNCTION__);
    return 0;
}
    
/*---------------------------------------------------------------------------*/

/*
 * JNI registration.
 */
static JNINativeMethod gPppoeMethods[] = {
    /* name,                    method descriptor,                              funcPtr */
    { "setupPppoeNative",       "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I",    (void *)setupPppoeNative },
    { "startPppoeNative",       "()I",                                          (void *)startPppoeNative },
    { "stopPppoeNative",        "()I",                                          (void *)stopPppoeNative },
    { "isPppoeUpNative",        "()I",                                          (void *)isPppoeUpNative },
};

int register_android_pppoe_PppoeNative(JNIEnv* env)
{
    return AndroidRuntime::registerNativeMethods(env, "com/android/server/PppoeService", gPppoeMethods, NELEM(gPppoeMethods) );
}
	
}

 

同时,需要加载进库中(上面的CPP文件并不是单独编译出一个SO, 一个放在AndroidRuntime库中)

frameworks/base/core/jni/AndroidRuntime.cpp

extern int register_android_net_LocalSocketImpl(JNIEnv* env);
extern int register_android_net_NetworkUtils(JNIEnv* env);
extern int register_android_net_TrafficStats(JNIEnv* env);
extern int register_android_net_wifi_WifiManager(JNIEnv* env);
//$_rbox_$_modify_$_chenzhi_20120309: add register_android_pppoe_PppoeNative
extern int register_android_pppoe_PppoeNative(JNIEnv* env);//引入
extern int register_android_text_AndroidCharacter(JNIEnv *env);
extern int register_android_text_AndroidBidi(JNIEnv *env);

同时,需要加入到:
static const RegJNIRec gRegJNI[] = {
    REG_JNI(register_android_debug_JNITest),
    REG_JNI(register_com_android_internal_os_RuntimeInit),
    REG_JNI(register_android_os_SystemClock),
    REG_JNI(register_android_util_EventLog),
    REG_JNI(register_android_util_Log),
    REG_JNI(register_android_util_FloatMath),
    REG_JNI(register_android_text_format_Time),
    REG_JNI(register_android_content_AssetManager),
    REG_JNI(register_android_content_StringBlock),
    REG_JNI(register_android_content_XmlBlock),
    REG_JNI(register_android_emoji_EmojiFactory),
    REG_JNI(register_android_text_AndroidCharacter),
    REG_JNI(register_android_text_AndroidBidi),
    REG_JNI(register_android_view_InputDevice),
    REG_JNI(register_android_view_KeyCharacterMap),
    REG_JNI(register_android_os_Process),
    REG_JNI(register_android_os_SystemProperties),
    REG_JNI(register_android_os_Binder),
    REG_JNI(register_android_os_Parcel),
    REG_JNI(register_android_view_Display),
    REG_JNI(register_android_view_DisplayEventReceiver),
    REG_JNI(register_android_nio_utils),
    REG_JNI(register_android_graphics_PixelFormat),
    REG_JNI(register_android_graphics_Graphics),
    REG_JNI(register_android_view_GLES20DisplayList),
    REG_JNI(register_android_view_GLES20Canvas),
    REG_JNI(register_android_view_HardwareRenderer),
    REG_JNI(register_android_view_Surface),
    REG_JNI(register_android_view_TextureView),
    REG_JNI(register_com_google_android_gles_jni_EGLImpl),
    REG_JNI(register_com_google_android_gles_jni_GLImpl),
    REG_JNI(register_android_opengl_jni_GLES10),
    REG_JNI(register_android_opengl_jni_GLES10Ext),
    REG_JNI(register_android_opengl_jni_GLES11),
    REG_JNI(register_android_opengl_jni_GLES11Ext),
	REG_JNI(register_android_pppoe_PppoeNative),//有时会忘记
	...
中

 

2. 系统启动后,添加服务:

frameworks/base/services/java/com/android/server/SystemServer.java
@Override
    public void run() {
	...
	//添加服务
			try {
				  Slog.i(TAG, "Pppoe Service");
				  pppoe = new PppoeService(context);
				  ServiceManager.addService(Context.PPPOE_SERVICE, pppoe);
			  } catch (Throwable e) {
				  reportWtf("starting Pppoe Service", e);
			  }
//$_rbox_$_modify_$_end
            try {
                Slog.i(TAG, "Throttle Service");
                throttle = new ThrottleService(context);
                ServiceManager.addService(
                        Context.THROTTLE_SERVICE, throttle);
            } catch (Throwable e) {
                reportWtf("starting ThrottleService", e);
            }

            try {
                Slog.i(TAG, "UpdateLock Service");
                ServiceManager.addService(Context.UPDATE_LOCK_SERVICE,
                        new UpdateLockService(context));
            } catch (Throwable e) {
                reportWtf("starting UpdateLockService", e);
            }

			

 

添加Manager

frameworks/base/core/java/android/app/ContextImpl.java
    static {
        registerService(ACCESSIBILITY_SERVICE, new ServiceFetcher() {
                public Object getService(ContextImpl ctx) {
                    return AccessibilityManager.getInstance(ctx);
                }});

        registerService(ACCOUNT_SERVICE, new ServiceFetcher() {
                public Object createService(ContextImpl ctx) {
                    IBinder b = ServiceManager.getService(ACCOUNT_SERVICE);
                    IAccountManager service = IAccountManager.Stub.asInterface(b);
                    return new AccountManager(ctx, service);
                }});
				
		registerService(PPPOE_SERVICE, new ServiceFetcher() {
				public Object createService(ContextImpl ctx) {
					IBinder b = ServiceManager.getService(PPPOE_SERVICE);
					IPppoeManager service = IPppoeManager.Stub.asInterface(b);
					return new PppoeManager(service, ctx.mMainThread.getHandler());
				}});		
			...

 

3. 如何使用?

 

XManager mgr = (XManager)context.getSystemService(name);

 

 

android 添加系统服务

  • 0

    开心

    开心

  • 0

    板砖

    板砖

  • 0

    感动

    感动

  • 0

    有用

    有用

  • 0

    疑问

    疑问

  • 0

    难过

    难过

  • 0

    无聊

    无聊

  • 0

    震惊

    震惊

编辑推荐
标记一下,以便以后查看 startup.bat 第一行插入以下两行 ( ps: 根据自己电脑来 ) SET JAVA_HOME=C:\
获取android系统中进程,任务,服务信息,需要通过ActivityManager类来实现。 ActivityManager的功
本文转自:http://www.cnblogs.com/yangxiao24/archive/2011/07/03/2096662.html 获取android系统中
学习参考:http://blog.csdn.net/luoshengyang/article/details/6642463 本博文将基于Binder扩展and
Android启动各种系统服务线程 SystemServer进程在Android的运行环境中扮演了"神经中枢"的作用,APK
当我们在编写咱们的应用程序的时候,有时候需要调用系统服务,做一些我们需要做的工作,比如调用输
运行cmd打开控制台,进入Tomat目录/bin文件夹,输入如下命令运行 service.bat install 运行结果如图
1、首先先来看一下修改前后的效果对比图 step1、插上3G设备前 如何修改Android设备添加3G上网功能_
1、首先先来看一下修改前后的效果对比图 step1、插上3G设备前 如何修改Android设备添加3G上网功能_
1、首先先来看一下修改前后的效果对比图 step1、插上3G设备前 如何修改Android设备添加3G上网功能_
版权所有 IT知识库 CopyRight © 2009-2015 IT知识库 IT610.com , All Rights Reserved. 京ICP备09083238号