中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當前位置: 首頁 > news >正文

鄭州商城網(wǎng)站建設(shè)多少錢一站式網(wǎng)站建設(shè)公司

鄭州商城網(wǎng)站建設(shè)多少錢,一站式網(wǎng)站建設(shè)公司,網(wǎng)絡(luò)安全企業(yè),有了域名怎樣做網(wǎng)站概述 在Android系統(tǒng)中,所有的應用程序進程以及系統(tǒng)服務進程SystemServer都是由Zygote進程孕育(fork)出來的,這也許就是為什么要把它稱為Zygote(受精卵)的原因吧。由于Zygote進程在Android系統(tǒng)中有著如此重…

概述

在Android系統(tǒng)中,所有的應用程序進程以及系統(tǒng)服務進程SystemServer都是由Zygote進程孕育(fork)出來的,這也許就是為什么要把它稱為Zygote(受精卵)的原因吧。由于Zygote進程在Android系統(tǒng)中有著如此重要的地位,本文將詳細分析它的啟動過程

總體時序

先概述一下總體運行流程,當按電源鍵,首先是加載系統(tǒng)引導程序BootLoader,然后啟動linux內(nèi)核,再啟動init進程,最后Zygote進程啟動完成。理論上Android系統(tǒng)中的所有應用程序理論上都是由Zygote啟動的。Zygote前期啟動啟動服務,后期主要fork程序。

init啟動流程

  • 用戶空間的第一個進程,進程號為1(在《深入理解安卓內(nèi)核思想》的257頁里面寫的是0,在這記錄一下)
  • 職責
  • 創(chuàng)建Zygote
  • 初始化屬性服務
  • init文件位于源碼目錄system/core/init中

init進程的啟動三個階段

  • 啟動電源以及系統(tǒng)的啟動,加載引導程序BootLoader。
  • 啟動Linux內(nèi)核
  • 啟動init進程。
  • 啟動Zygote進程
  • 初始化啟動屬性服務。

Zygote進程

  • 所有App的父進程,ZygoteInit.main
  • Zygote進程,是由init進程通過解析init.rc文件后fork生成的,Zygote進程主要包括
  • 加載Zygoteinit類,注冊Zygote Socket服務端套接字
  • 加載虛擬機
  • 提前加載類PreloadClasses
  • 提前加載資源PreLoadResouces
  • system_server進程,是由Zygote fork而來,System Server是Zygote孵化出的第一個進程,System Server 負責啟動和管理整個Java FrameWork,包含ActivityManagerService, WorkManagerService,PagerManagerService,PowerManagerService等服務

system_server進程

系統(tǒng)各大服務的載體, SystemServer.main system_server進程從源碼角度來看可以分為,引導服務,核心服務和其他服務

  • 引導服務(7個):ActivityManagerService、PowerManagerService、LightsService、DisplayManagerService、PackageManagerService、UserManagerService、SensorService;
  • 核心服務(3個):BatteryService、UsageStatsService、WebViewUpdateService;
  • 其他服務(70個+):AlarmManagerService、VibratorService等。

ServiceManger進程

bInder服務的大管家

ServiceManager 是Binder IPC通信過程中的守護進程,本身也是一個Binder,但是并沒有采用多線程模型來跟Binder通信,而是自行編寫了binder.c直接和Binder驅(qū)動來通信,并且只有一個binder_loop來讀取和處理事務,這樣做的好處是簡單和高效 ServiceManager本身工作相對簡單,其工能查詢和注冊服務

流程圖

ServiceManager 集中管理系統(tǒng)內(nèi)的所有服務,通能過權(quán)限控制進程是否有權(quán)注冊服務,通過字符串來查找是否有對應的Service,由于ServiceManager進程注冊了Service的死亡通知,那么服務所在的進程死亡后,只需告訴ServiceManager,每個Client通過查詢ServiceManager可以獲取Service的情況

啟動主要包括以下幾個階段

  • 打開Binder驅(qū)動,并調(diào)用mmap()方法分配128k的內(nèi)存映射空間,binder_open
  • 注冊成為Binder服務的大管家binder_become_context_manager
  • 驗證selinux權(quán)限,判斷進程是否有權(quán)注冊查看指定服務
  • 進入無限循環(huán),處理Client發(fā)來的請求 binder_loop
  • 根據(jù)服務的名稱注冊服務,重復注冊會移除之前的注冊信息
  • 死亡通知,當所在進程死亡后,調(diào)用binder_release方法,然后調(diào)用binder_node_release,這個過程發(fā)出死亡通知回調(diào)

App進程

  • 通過Process.start啟動的App進程ActivityThread.main
  • Zygote 孵化出的第一個App進程是Launcher,這是用戶看到的桌面App
  • Zygote 還會創(chuàng)建出Browser,Phone,Email等App進程,每個App至少運行在一個進程上
  • 所有的App進程都是由Zygote fork而成

3)Zygote進程的啟動

Zygote進程, 一個在Android系統(tǒng)中扮演重要角色的進程. 我們知道Android系統(tǒng)中的兩個重要服務PackageManagerService和ActivityManagerService, 都是由SystemServer進程啟動的, 而這個SystemServer進程本身是Zygote進程在啟動的過程中fork出來的. 這樣一來, 想必我們就知道Zygote進程在Android系統(tǒng)中的重要地位了.

從圖中可得知Android系統(tǒng)中各個進程的先后順序為:

init進程 –-> Zygote進程 –> SystemServer進程 –>應用進程

鏈接

  1. 在init啟動Zygote時主要是調(diào)用app_main.cpp的main函數(shù)中的AppRuntime.start()方法來啟動Zygote進程的;
  2. 接著到AndroidRuntime的start函數(shù):使用JNI調(diào)用ZygoteInit的main函數(shù),之所以這里要使用JNI,是因為ZygoteInit是java代碼。最終,Zygote就從Native層進入了Java FrameWork層。在此之前,并沒有任何代碼進入Java FrameWork層面,因此可以認為,Zygote開創(chuàng)了java FrameWork層。
  3. /frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
    @UnsupportedAppUsagepublic static void main(String argv[]) {ZygoteServer zygoteServer = null;// Mark zygote start. This ensures that thread creation will throw// an error.ZygoteHooks.startZygoteNoThreadCreation();// Zygote goes into its own process group.try {Os.setpgid(0, 0);} catch (ErrnoException ex) {throw new RuntimeException("Failed to setpgid(0,0)", ex);}Runnable caller;try {// Report Zygote start time to tron unless it is a runtime restartif (!"1".equals(SystemProperties.get("sys.boot_completed"))) {MetricsLogger.histogram(null, "boot_zygote_init",(int) SystemClock.elapsedRealtime());}String bootTimeTag = Process.is64Bit() ? "Zygote64Timing" : "Zygote32Timing";TimingsTraceLog bootTimingsTraceLog = new TimingsTraceLog(bootTimeTag,Trace.TRACE_TAG_DALVIK);bootTimingsTraceLog.traceBegin("ZygoteInit");RuntimeInit.enableDdms();boolean startSystemServer = false;String zygoteSocketName = "zygote";String abiList = null;boolean enableLazyPreload = false;for (int i = 1; i < argv.length; i++) {if ("start-system-server".equals(argv[i])) {startSystemServer = true;} else if ("--enable-lazy-preload".equals(argv[i])) {enableLazyPreload = true;} else if (argv[i].startsWith(ABI_LIST_ARG)) {abiList = argv[i].substring(ABI_LIST_ARG.length());} else if (argv[i].startsWith(SOCKET_NAME_ARG)) {zygoteSocketName = argv[i].substring(SOCKET_NAME_ARG.length());} else {throw new RuntimeException("Unknown command line argument: " + argv[i]);}}final boolean isPrimaryZygote = zygoteSocketName.equals(Zygote.PRIMARY_SOCKET_NAME);if (abiList == null) {throw new RuntimeException("No ABI list supplied.");}// In some configurations, we avoid preloading resources and classes eagerly.// In such cases, we will preload things prior to our first fork.if (!enableLazyPreload) {bootTimingsTraceLog.traceBegin("ZygotePreload");EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,SystemClock.uptimeMillis());preload(bootTimingsTraceLog);EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,SystemClock.uptimeMillis());bootTimingsTraceLog.traceEnd(); // ZygotePreload} else {Zygote.resetNicePriority();}// Do an initial gc to clean up after startupbootTimingsTraceLog.traceBegin("PostZygoteInitGC");gcAndFinalize();bootTimingsTraceLog.traceEnd(); // PostZygoteInitGCbootTimingsTraceLog.traceEnd(); // ZygoteInit// Disable tracing so that forked processes do not inherit stale tracing tags from// Zygote.Trace.setTracingEnabled(false, 0);Zygote.initNativeState(isPrimaryZygote);ZygoteHooks.stopZygoteNoThreadCreation();zygoteServer = new ZygoteServer(isPrimaryZygote);if (startSystemServer) {
// 使用了forkSystemServer()方法去創(chuàng)建SystemServer進程Runnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer);
// {@code r == null} in the parent (zygote) process, and {@code r != null} in the
// child (system_server) process.if (r != null) {r.run();return;
}
}
Log.i(TAG, "Accepting command socket connections");
// The select loop returns early in the child process after a fork and
// 這里調(diào)用了ZygoteServer的runSelectLoop方法來等等ActivityManagerService來請求創(chuàng)建新的應用程序進程            
// loops forever in the zygote.caller = zygoteServer.runSelectLoop(abiList);} 
catch (Throwable ex) {
Log.e(TAG, "System zygote died with exception", ex);
throw ex;} 
finally 
{
if (zygoteServer != null) {zygoteServer.closeServerSocket();
}
}
// We're in the child process and have exited the select loop. Proceed to execute the
// command.if (caller != null) {caller.run();
}
}

其中, 在ZygoteInit的forkSystemServer()方法中啟動了SystemServer進程,forkSystemServer()方法核心代碼 :

private static Runnable forkSystemServer(String abiList, String socketName,ZygoteServer zygoteServer) 
{
// 一系統(tǒng)創(chuàng)建SystemServer進程所需參數(shù)的準備工作try {...
/* Request to fork the system server process 
*/// 3.1pid = Zygote.forkSystemServer(parsedArgs.uid, parsedArgs.gid,parsedArgs.gids,parsedArgs.runtimeFlags,null,parsedArgs.permittedCapabilities,parsedArgs.effectiveCapabilities);
} 
catch (IllegalArgumentException ex) 
{throw new RuntimeException(ex);}
/* For child process 
*/if (pid == 0) {
if (hasSecondZygote(abiList)) {waitForSecondaryZygote(socketName);}
zygoteServer.closeServerSocket();
// 3.2return handleSystemServerProcess(parsedArgs);
}return null;
}

可以看到,forkSystemServer()方法中,注釋3.1調(diào)用了Zygote的forkSystemServer()方法去創(chuàng)建SystemServer進程,其內(nèi)部會執(zhí)行nativeForkSystemServer這個Native方法,它最終會使用fork函數(shù)在當前進程創(chuàng)建一個SystemServer進程。如果pid等于0,即當前是處于新創(chuàng)建的子進程ServerServer進程中,則在注釋3.2處使用handleSystemServerProcess()方法處理SystemServer進程的一些處理工作。

從以上的分析可以得知,Zygote進程啟動中承擔的主要職責如下:

  • 1、創(chuàng)建AppRuntime,執(zhí)行其start方法,啟動Zygote進程。。
  • 2、創(chuàng)建JVM并為JVM注冊JNI方法。
  • 3、使用JNI調(diào)用ZygoteInit的main函數(shù)進入Zygote的Java FrameWork層。
  • 4、使用registerZygoteSocket方法創(chuàng)建服務器端Socket,并通過runSelectLoop方法等等AMS的請求去創(chuàng)建新的應用進程。
  • 5、啟動SystemServer進程。
  1. 調(diào)用了handleSystemServerprocess()方法來啟動SystemServer進程。handleSystemServerProcess()方法如下所示:
/*** Finish remaining work for the newly forked system server process.
*/
private static Runnable handleSystemServerProcess(ZygoteConnection.Arguments parsedArgs) {...
if (parsedArgs.invokeWith != null) {...} 
else {ClassLoader cl = null;
if (systemServerClasspath != null) {
// 1cl = createPathClassLoader(systemServerClasspath, parsedArgs.targetSdkVersion);
Thread.currentThread().setContextClassLoader(cl);}
/** Pass the remaining arguments to SystemServer.
*/// 2return ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, cl);
}
}

在注釋1處,使用了systemServerClassPath和targetSdkVersion創(chuàng)建了一個PathClassLoader。接著,在注釋2處,執(zhí)行了ZygoteInit的zygoteInit()方法,該方法如下所示:

public static final Runnable zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader) 
{
if (RuntimeInit.DEBUG) {
Slog.d(RuntimeInit.TAG, "RuntimeInit: Starting application from zygote");
}
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ZygoteInit");
RuntimeInit.redirectLogStreams();
RuntimeInit.commonInit();
// 1ZygoteInit.nativeZygoteInit();
// 2return RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
}
  1. zygoteInit()方法的注釋2處,這里調(diào)用了RuntimeInit 的 applicationInit() 方法,代碼如下所示:

/frameworks/base/core/java/com/android/internal/os/RuntimeInit.java

protected static Runnable applicationInit(int targetSdkVersion, String[] argv,ClassLoader classLoader) {...
// Remaining arguments are passed to the start class's static mainreturn findStaticMain(args.startClass, args.startArgs, classLoader);
}

在applicationInit()方法中最后調(diào)用了findStaticMain()方法:

protected static Runnable findStaticMain(String className, String[] argv,ClassLoader classLoader) {
Class<?> cl;
try {
// 1cl = Class.forName(className, true, classLoader);
} 
catch (ClassNotFoundException ex) {
throw new RuntimeException("Missing class when invoking static main " + className,ex);
}
Method m;try {
// 2m = cl.getMethod("main", new Class[] { String[].class });
} 
catch (NoSuchMethodException ex) {
throw new RuntimeException("Missing static main on " + className, ex);} 
catch (SecurityException ex) {throw new RuntimeException("Problem getting static main on " + className, ex);}
int modifiers = m.getModifiers();
if (! (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) {
throw new RuntimeException("Main method is not public and static on " + className);}
/** This throw gets caught in ZygoteInit.main(), which responds
* by invoking the exception's run() method. This arrangement
* clears up all the stack frames that were required in setting
* up the process.
*/// 3return new MethodAndArgsCaller(m, argv);
}

首先,在注釋1處,通過發(fā)射得到了SystemServer類。接著,在注釋2處,找到了SystemServer中的main()方法。最后,在注釋3處,會將main()方法傳入MethodAndArgsCaller()方法中,這里的MethodAndArgsCaller()方法是一個Runnable實例,它最終會一直返回出去,直到在ZygoteInit的main()方法中被使用,如下所示:

if (startSystemServer) {
Runnable r = forkSystemServer(abiList, socketName, zygoteServer);
// {@code r == null} 
in the parent (zygote) process, and {
@code r != null} 
in the
// child (system_server) process.
if (r != null) {
r.run();
return;
}
}

可以看到,最終直接調(diào)用了這個Runnable實例的run()方法,代碼如下所示:

/*** Helper class which holds a method and arguments and can call them. This is used as part of
* a trampoline to get rid of the initial process setup stack frames.
*/
static class MethodAndArgsCaller implements Runnable {
/** method to call 
*/private final Method mMethod;
/** argument array 
*/private final String[] mArgs;public MethodAndArgsCaller(Method method, String[] args) {
mMethod = method;mArgs = args;}
public void run() {try {
// 1mMethod.invoke(null, new Object[] { 
mArgs });} 
catch (IllegalAccessException ex) {throw new RuntimeException(ex);} 
catch (InvocationTargetException ex) {
Throwable cause = ex.getCause();
if (cause instanceof RuntimeException) {
throw (RuntimeException) cause;
} 
else if (cause instanceof Error) {
throw (Error) cause;}
throw new RuntimeException(ex);
}
}
}

在注釋1處,這個mMethod就是指的SystemServer的main()方法,這里動態(tài)調(diào)用了SystemServer的main()方法,最終,SystemServer進程就進入了SystemServer的main()方法中了。這里還有個遺留問題,為什么不直接在findStaticMain()方法中直接動態(tài)調(diào)用SystemServer的main()方法呢?原因就是這種遞歸返回后再執(zhí)行入口方法的方式會讓SystemServer的main()方法看起來像是SystemServer的入口方法,而且,這樣也會清除之前所有SystemServer相關(guān)設(shè)置過程中需要的堆棧幀。

--------走到 SystemService 進程

  1. /frameworks/base/services/java/com/android/server/SystemServer.java

接下來我們看看SystemServer的main()方法:

/**
* The main entry point from zygote.
*/
public static void main(String[] args) 
{
new SystemServer().run();
}

main()方法中調(diào)用了SystemServer的run()方法,如下所示:

private void run() {try {...
// 1Looper.prepareMainLooper();...
// Initialize native services.
// 2System.loadLibrary("android_servers");
// Check whether we failed to shut down last time we tried.
// This call may not return.performPendingShutdown();
// Initialize the system context.createSystemContext();
// Create the system service manager.
// 3mSystemServiceManager = new SystemServiceManager(mSystemContext);
mSystemServiceManager.setStartInfo(mRuntimeRestart,mRuntimeStartElapsedTime, mRuntimeStartUptime);
LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);
// Prepare the thread pool for init tasks that can be parallelizedSystemServerInitThreadPool.get();} 
finally {traceEnd();  
// InitBeforeStartServices}
// Start services.try {
traceBeginAndSlog("StartServices");
// 4startBootstrapServices();
// 5startCoreServices();
//6startOtherServices();
SystemServerInitThreadPool.shutdown();} 
catch (Throwable ex) {Slog.e("System", "******************************************");
Slog.e("System", "************ Failure starting system services", ex);
throw ex;} 
finally {
traceEnd();
}...
// Loop forever.
// 7Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}

在注釋1處,創(chuàng)建了消息Looper。

在注釋2處,加載了動態(tài)庫libandroid_servers.so。

在注釋3處,創(chuàng)建了SystemServerManager,它的作用是對系統(tǒng)服務進行創(chuàng)建、啟動和生命周期管理。

在注釋4處的startBootstarpServices()方法中使用SystemServiceManager啟動了ActivityManagerService、PackageManagerService、PowerManagerService等引導服務。

在注釋5處的startCoreServices()方法中則啟動了BatteryService、WebViewUpdateService、DropBoxManagerService、UsageStatsService4個核心服務。

在注釋6處的startOtherServices()方法中啟動了WindowManagerService、InputManagerService、CameraService等其它服務。這些服務的父類都是SystemService。

可以看到,上面把系統(tǒng)服務分成了三種類型:引導服務、核心服務、其它服務。這些系統(tǒng)服務共有100多個,其中對于我們來說比較關(guān)鍵的有:

  • 引導服務:ActivityManagerService,負責四大組件的啟動、切換、調(diào)度。
  • 引導服務:PackageManagerService,負責對APK進行安裝、解析、刪除、卸載等操作。
  • 引導服務:PowerManagerService,負責計算系統(tǒng)中與Power相關(guān)的計算,然后決定系統(tǒng)該如何反應。
  • 核心服務:BatteryService,管理電池相關(guān)的服務。
  • 其它服務:WindowManagerService,窗口管理服務。
  • 其它服務:InputManagerService,管理輸入事件。

很多系統(tǒng)服務的啟動邏輯都是類似的,這里我以啟動ActivityManagerService服務來進行舉例,代碼如下所示:

mActivityManagerService = mSystemServiceManager.startService(ActivityManagerService.Lifecycle.class).getService();

SystemServiceManager 的 startService() 方法啟動了ActivityManagerService,該啟動方法如下所示:

@SuppressWarnings("unchecked")
public <T extends SystemService> T startService(Class<T> serviceClass) {
try {final String name = serviceClass.getName();
...try {Constructor<T> constructor = serviceClass.getConstructor(Context.class);
// 1service = constructor.newInstance(mContext);
} 
catch (InstantiationException ex) {...
// 2startService(service);return service;
} 
finally {Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
}
}

在注釋1處使用反射創(chuàng)建了ActivityManagerService實例,并在注釋2處調(diào)用了另一個startService()重載方法,如下所示:

public void startService(@NonNull final SystemService service) {
// Register it.
// 1mServices.add(service);
// Start it.long time = SystemClock.elapsedRealtime();
try {
// 2service.onStart();
} 
catch (RuntimeException ex) 
{
throw new RuntimeException("Failed to start service " + service.getClass().getName()+ ": onStart threw an exception", ex);
}
warnIfTooLong(SystemClock.elapsedRealtime() - time, service, "onStart");
}

在注釋1處,首先會將ActivityManagerService添加在mServices中,它是一個存儲SystemService類型的ArrayList,這樣就完成了ActivityManagerService的注冊。

在注釋2處,調(diào)用了ActivityManagerService的onStart()方法完成了啟動ActivityManagerService服務。

除了使用SystemServiceManager的startService()方法來啟動系統(tǒng)服務外,也可以直接調(diào)用服務的main()方法來啟動系統(tǒng)服務,如PackageManagerService:

mPackageManagerService = PackageManagerService.main(mSystemContext, installer,mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);

這里直接調(diào)用了PackageManagerService的main()方法:

public static PackageManagerService main(Context context, Installer installer,boolean factoryTest, boolean onlyCore) {
// Self-check for initial settings.PackageManagerServiceCompilerMapping.checkProperties();
// 1PackageManagerService m = new PackageManagerService(context, installer,factoryTest, onlyCore);
m.enableSystemUserPackages();
// 2ServiceManager.addService("package", m);
// 3final PackageManagerNative pmn = m.new PackageManagerNative();
ServiceManager.addService("package_native", pmn);
return m;
}

在注釋1處,直接新建了一個PackageManagerService實例,

注釋2處將PackageManagerService注冊到服務大管家ServiceManager中,ServiceManager用于管理系統(tǒng)中的各種Service,用于系統(tǒng)C/S架構(gòu)中的Binder進程間通信,即如果Client端需要使用某個Servcie,首先應該到ServiceManager查詢Service的相關(guān)信息,然后使用這些信息和該Service所在的Server進程建立通信通道,這樣Client端就可以服務端進程的Service進行通信了。

7. SystemService 進程總結(jié)

SystemService的啟動流程分析至此已經(jīng)完結(jié),經(jīng)過以上的分析可知,SystemService進程被創(chuàng)建后,主要的處理如下:

  • 1、啟動Binder線程池,這樣就可以與其他進程進行Binder跨進程通信。
  • 2、創(chuàng)建SystemServiceManager,它用來對系統(tǒng)服務進行創(chuàng)建、啟動和生命周期管理。
  • 3、啟動各種系統(tǒng)服務:引導服務、核心服務、其他服務,共100多種。應用開發(fā)主要關(guān)注引導服務ActivityManagerService、PackageManagerService和其他服務WindowManagerService、InputManagerService即可。
http://www.risenshineclean.com/news/54548.html

相關(guān)文章:

  • 有沒有專業(yè)做二維碼連接網(wǎng)站在口碑營銷案例簡短
  • 學php做網(wǎng)站品牌營銷包括哪些方面
  • 網(wǎng)站建設(shè)與網(wǎng)頁設(shè)計的論文軟文范例大全800
  • 網(wǎng)站開發(fā)算什么費用知乎關(guān)鍵詞排名工具
  • 做外商備案的網(wǎng)站百度官方app免費下載
  • 免費的軟件網(wǎng)站seo運營學校
  • 電力建設(shè)期刊網(wǎng)站上海網(wǎng)站推廣廣告
  • 陜西網(wǎng)站制作商學電腦在哪里報名
  • 深圳做網(wǎng)站建設(shè)的公司競價交易規(guī)則
  • 網(wǎng)站建設(shè)的公司哪家是上市公司百度搜索推廣產(chǎn)品
  • 攝影網(wǎng)站建設(shè)內(nèi)容濟南網(wǎng)站優(yōu)化排名推廣
  • 東莞微網(wǎng)站制作網(wǎng)站seo思路
  • 做網(wǎng)站的優(yōu)勢有哪些國家域名注冊服務網(wǎng)
  • 網(wǎng)站 公眾號 建設(shè)方案谷歌廣告推廣怎么做
  • 做網(wǎng)站流程、上海抖音推廣
  • 怎么做付款下載網(wǎng)站上海網(wǎng)站建設(shè)方案
  • 蘇州電商網(wǎng)站建設(shè)站長工具服務器查詢
  • 百度怎么做自己的網(wǎng)站怎么在百度上發(fā)帖推廣
  • 投票網(wǎng)站開發(fā)的背景和意義免費網(wǎng)站seo排名優(yōu)化
  • 用淘寶域名做網(wǎng)站什么效果百度口碑網(wǎng)
  • 北京工商注冊代理記賬最新黑帽seo培訓
  • 公司網(wǎng)站在國外打開很慢使用cdn好還是國外租用服務器好互聯(lián)網(wǎng)營銷推廣公司
  • 電商網(wǎng)站的建設(shè)與維護域名查詢網(wǎng)址
  • 最新百度快速收錄技術(shù)seo軟件定制
  • 淘寶上做網(wǎng)站的信得過嗎手機系統(tǒng)優(yōu)化軟件
  • 國外網(wǎng)站推廣百度查詢
  • 如何制作網(wǎng)站的app海會網(wǎng)絡(luò)做的網(wǎng)站怎么做優(yōu)化
  • 免費網(wǎng)頁設(shè)計作業(yè)文件seo屬于什么職業(yè)部門
  • 優(yōu)化方案物理電子版百度信息流優(yōu)化
  • 普通網(wǎng)站要什么費用推廣軟文300字范文