目录

1、Zygote简介

2、Zygote进程如何启动

  2.1 init.zygote64_32.rc文件

  2.2 查看ps信息

  2.3 启动

3、Zygote作用

  3.1 启动system_server

  3.2 查看与验证Zygote启动systemserver

  3.3 Zygote启动其他子进程

4、总结

1、Zygote简介

  • 1.1 系统启动流程

    • 从按下电源到看到launcher,手机的启动是一个非常复杂的过程。

      bootloader是手机上电之后第一个运行的程序,其作用是硬件的初始化,其作用类似于PC机的bios。

      bootloader完成其工作后,将 Linux kernel镜像拷贝到内存中。完成剩余的与硬件平台相关的初始化工作,比如文件系统,驱动模块。最后启动第一个用户进程-init 进程并等待用户进程的执行。

      用户空间的第一个进程init

  • 1.2 zygote理解
    • 在Android系统中,所有的应用程序进程以及系统服务进程SystemServer都是由Zygote进程孕育(fork)出来的。由于Zygote进程在Android系统中有着如此重要的地位,本文将详细分析它的启动过程。---老罗
    • android系统中创建java世界的盘古  创建新进程的女娲。 ---邓凡平

2、Zygote进程如何启动

  • 2.1 init.zygote64_32.rc文件

    • system/core/rootdir/init.zygote64_32.rc文件内容
      1. 1 service zygote /system/bin/app_process32 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote
      2. 2 class main
      3. 3 socket zygote stream 660 root system
      4. 4 onrestart write /sys/android_power/request_state wake
      5. 5 onrestart write /sys/power/state on
      6. 6 onrestart restart media
      7. 7 onrestart restart netd
      8. 8
      9. 9 service zygote_secondary /system/bin/app_process64 -Xzygote /system/bin --zygote --socket-name=zygote_secondary
      10. 10 class main
      11. 11 socket zygote_secondary stream 660 root system
      12. 12 onrestart restart zygote
  • 2.2 查看ps信息
    • Zygote64、Zygote是在init.rc中定义的服务进程,由init进程启动,PPID均为1。其中比较关键的vold、rild、surfaceflinger等关键进程也都是通过init进程启动的。

    • LOCAL_MULTILIB: Android.mk中用来设置编译为32位或者64位的apk,so等

  • 2.3 启动
    • Zygote process main(frameworks/base/cmds/app_process/app_main.cpp)
      1. 1 int main(int argc, char* const argv[])
      2. 2 {
      3. 3 ...
      4. 121 if (zygote) {
      5. 122 runtime.start("com.android.internal.os.ZygoteInit", args);
      6. 123 } else if (className) {
      7. 124 runtime.start("com.android.internal.os.RuntimeInit", args);
      8. 125 } else {
      9. 126 fprintf(stderr, "Error: no class name or --zygote supplied.\n");
      10. 127 app_usage();
      11. 128 LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
      12. 129 return 10;
      13. 130 }
      14. 131 }
    • 将init.rc中指定的-Xzygote参数传给JVM
      将进程的名字改为zygote(可以回答前面的问题)
      执行AppRuntime类的start()方法,runtime.start(“com.android.internal.os.ZygoteInit”, true);
      1. 1 void AndroidRuntime::start(const char* className, const Vector<String8>& options)
      2. 2 {
      3. 3 ...
      4. 30 //const char* kernelHack = getenv("LD_ASSUME_KERNEL");
      5. 31 //ALOGD("Found LD_ASSUME_KERNEL='%s'\n", kernelHack);
      6. 32
      7. 33 /* start the virtual machine */
      8. 34 JniInvocation jni_invocation;
      9. 35 jni_invocation.Init(NULL);
      10. 36 JNIEnv* env;
      11. 37 if (startVm(&mJavaVM, &env) != 0) {
      12. 38 return;
      13. 39 }
      14. 40 onVmCreated(env);
      15. 41
      16. 42 /*
      17. 43 * Register android functions.
      18. 44 */
      19. 45 if (startReg(env) < 0) {
      20. 46 ALOGE("Unable to register all android natives\n");
      21. 47 return;
      22. 48 }
      23. 49
      24. 50 /*
      25. 51 * We want to call main() with a String array with arguments in it.
      26. 52 * At present we have two arguments, the class name and an option string.
      27. 53 * Create an array to hold them.
      28. 54 */
      29. 55 jclass stringClass;
      30. 56 jobjectArray strArray;
      31. 57 jstring classNameStr;
      32. 58
      33. 59 stringClass = env->FindClass("java/lang/String");
      34. 60 assert(stringClass != NULL);
      35. 61 strArray = env->NewObjectArray(options.size() + 1, stringClass, NULL);
      36. 62 assert(strArray != NULL);
      37. 63 classNameStr = env->NewStringUTF(className);
      38. 64 assert(classNameStr != NULL);
      39. 65 env->SetObjectArrayElement(strArray, 0, classNameStr);
      40. 66
      41. 67 for (size_t i = 0; i < options.size(); ++i) {
      42. 68 jstring optionsStr = env->NewStringUTF(options.itemAt(i).string());
      43. 69 assert(optionsStr != NULL);
      44. 70 env->SetObjectArrayElement(strArray, i + 1, optionsStr);
      45. 71 }
      46. 72
      47. 73 /*
      48. 74 * Start VM. This thread becomes the main thread of the VM, and will
      49. 75 * not return until the VM exits.
      50. 76 */
      51. 77 char* slashClassName = toSlashClassName(className);
      52. 78 jclass startClass = env->FindClass(slashClassName);
      53. 79 if (startClass == NULL) {
      54. 80 ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
      55. 81 /* keep going */
      56. 82 } else {
      57. 83 jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
      58. 84 "([Ljava/lang/String;)V");
      59. 85 if (startMeth == NULL) {
      60. 86 ALOGE("JavaVM unable to find main() in '%s'\n", className);
      61. 87 /* keep going */
      62. 88 } else {
      63. 89 env->CallStaticVoidMethod(startClass, startMeth, strArray);
      64. 90
      65. 91 #if 0
      66. 92 if (env->ExceptionCheck())
      67. 93 threadExitUncaughtException(env);
      68. 94 #endif
      69. 95 }
      70. 96 }
      71. 97 free(slashClassName);
      72. 98
      73. 99 ALOGD("Shutting down VM\n");
      74. 100 if (mJavaVM->DetachCurrentThread() != JNI_OK)
      75. 101 ALOGW("Warning: unable to detach main thread\n");
      76. 102 if (mJavaVM->DestroyJavaVM() != 0)
      77. 103 ALOGW("Warning: VM did not shut down cleanly\n");
      78. 104 }
    • runtime.start函数,即在frameworks\base\core\jni\AndroidRuntime.cpp文件中
      • AndroidRuntime::startVm()中,设置一些虚拟机的参数后,通过JNI_CreateJavaVM()启动虚拟机。
      • StartReg()注册JNI 函数
      • env->CallStaticVoidMethod,调用ZygoteInit类的main()方法,正式进入到Java世界.
    • frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
      1. public static void main(String argv[]) {
      2. try {
      3. ....
      4. registerZygoteSocket(socketName);
      5. EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
      6. SystemClock.uptimeMillis());
      7. preload();
      8. EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
      9. SystemClock.uptimeMillis());
      10.  
      11. // Finish profiling the zygote initialization.
      12. SamplingProfilerIntegration.writeZygoteSnapshot();
      13.  
      14. // Do an initial gc to clean up after startup
      15. gc();
      16.  
      17. // Disable tracing so that forked processes do not inherit stale tracing tags from
      18. // Zygote.
      19. Trace.setTracingEnabled(false);
      20.  
      21. if (startSystemServer) {
      22. startSystemServer(abiList, socketName);
      23. }
      24.  
      25. Log.i(TAG, "Accepting command socket connections");
      26. runSelectLoop(abiList);
      27.  
      28. closeServerSocket();
      29. } catch (MethodAndArgsCaller caller) {
      30. caller.run();
      31. } catch (RuntimeException ex) {
      32. Log.e(TAG, "Zygote died with exception", ex);
      33. closeServerSocket();
      34. throw ex;
      35. }
      36. }
    • registerZygoteSocket,创建Socket服务端对象sServerSocket

      preload方法预加载类,资源等

      调用startSystemServer方法启动系统服务system_server

      runSelectLoopMode监听和处理sServerSocket的Socket请求

  • 3、Zygote作用
    • 3.1 启动system_server

        1. 1 /**
        2. 2 * Prepare the arguments and fork for the system server process.
        3. 3 */
        4. 4 private static boolean startSystemServer(String abiList, String socketName)
        5. 5 throws MethodAndArgsCaller, RuntimeException {
        6. 6 ...
        7. 31 int pid;
        8. 32
        9. 33 try {
        10. 34 parsedArgs = new ZygoteConnection.Arguments(args);
        11. 35 ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);
        12. 36 ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);
        13. 37
        14. 38 /* Request to fork the system server process */
        15. 39 pid = Zygote.forkSystemServer(
        16. 40 parsedArgs.uid, parsedArgs.gid,
        17. 41 parsedArgs.gids,
        18. 42 parsedArgs.debugFlags,
        19. 43 null,
        20. 44 parsedArgs.permittedCapabilities,
        21. 45 parsedArgs.effectiveCapabilities);
        22. 46 } catch (IllegalArgumentException ex) {
        23. 47 throw new RuntimeException(ex);
        24. 48 }
        25. 49
        26. 50 /* For child process */
        27. 51 if (pid == 0) {//子进程进入
        28. 52 if (hasSecondZygote(abiList)) {
        29. 53 waitForSecondaryZygote(socketName);
        30. 54 }
        31. 55
        32. 56 handleSystemServerProcess(parsedArgs);
        33. 57 }
        34. 58
        35. 59 return true;
        36. 60 }
      • forkSystemServer,调用Native方法fork子进程
        通过forkSystemServer方法返回的值,进入两个分支处理:父进程返回子进程pid值,进入到ZygoteInit类中的main方法继续处理;而子进程调用handleSystemServerProcess方法,最终会运行system_server。
        1. 1 /**
        2. 2 * Finish remaining work for the newly forked system server process.
        3. 3 */
        4. 4 private static void handleSystemServerProcess(
        5. 5 ZygoteConnection.Arguments parsedArgs)
        6. 6 throws ZygoteInit.MethodAndArgsCaller {
        7. 7
        8. 8 closeServerSocket();//子进程已经不是服务器了,所以关掉。
        9. 9
        10. 10 // set umask to 0077 so new files and directories will default to owner-only permissions.
        11. 11 Os.umask(S_IRWXG | S_IRWXO);
        12. 12
        13. 13 if (parsedArgs.niceName != null) {
        14. 14 Process.setArgV0(parsedArgs.niceName);
        15. 15 }
        16. 16
        17. 17 final String systemServerClasspath = Os.getenv("SYSTEMSERVERCLASSPATH");
        18. 18 if (systemServerClasspath != null) {
        19. 19 performSystemServerDexOpt(systemServerClasspath);
        20. 20 }
        21. 21
        22. 22 if (parsedArgs.invokeWith != null) {
        23. 23 String[] args = parsedArgs.remainingArgs;
        24. 24 // If we have a non-null system server class path, we'll have to duplicate the
        25. 25 // existing arguments and append the classpath to it. ART will handle the classpath
        26. 26 // correctly when we exec a new process.
        27. 27 if (systemServerClasspath != null) {
        28. 28 String[] amendedArgs = new String[args.length + 2];
        29. 29 amendedArgs[0] = "-cp";
        30. 30 amendedArgs[1] = systemServerClasspath;
        31. 31 System.arraycopy(parsedArgs.remainingArgs, 0, amendedArgs, 2, parsedArgs.remainingArgs.length);
        32. 32 }
        33. 33
        34. 34 WrapperInit.execApplication(parsedArgs.invokeWith,
        35. 35 parsedArgs.niceName, parsedArgs.targetSdkVersion,
        36. 36 null, args);
        37. 37 } else {
        38. 38 ClassLoader cl = null;
        39. 39 if (systemServerClasspath != null) {
        40. 40 cl = new PathClassLoader(systemServerClasspath, ClassLoader.getSystemClassLoader());
        41. 41 Thread.currentThread().setContextClassLoader(cl);
        42. 42 }
        43. 43
        44. 44 /*
        45. 45 * Pass the remaining arguments to SystemServer.
        46. 46 */
        47. 47 RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, cl);
        48. 48 }
        49. 49
        50. 50 /* should never reach here */
        51. 51 }
      • frameworks/base/core/java/com/android/internal/os/RuntimeInit.java
        1. 43 public class RuntimeInit {
        2. 44 。。。
        3. 197 private static void invokeStaticMain(String className, String[] argv, ClassLoader classLoader)
        4. 198 throws ZygoteInit.MethodAndArgsCaller {
        5. 199 。。。
        6. 232 throw new ZygoteInit.MethodAndArgsCaller(m, argv);
        7. 233 }
        8. 267 public static final void zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
        9. 268 throws ZygoteInit.MethodAndArgsCaller {
        10. 269 if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application from zygote");
        11. 270
        12. 271 redirectLogStreams();
        13. 272
        14. 273 commonInit();
        15. 274 nativeZygoteInit();
        16. 275
        17. 276 applicationInit(targetSdkVersion, argv, classLoader);
        18. 277 }
        19. 297 private static void applicationInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
        20. 298 throws ZygoteInit.MethodAndArgsCaller {
        21. 299 。。。
        22. 308 VMRuntime.getRuntime().setTargetHeapUtilization(0.75f);
        23. 309 VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion);
        24. 310
        25. 311 。。。
        26. 320 // Remaining arguments are passed to the start class's static main
        27. 321 invokeStaticMain(args.startClass, args.startArgs, classLoader);
        28. 322 }
        29. 363 public static final IBinder getApplicationObject() {
        30. 364 return mApplicationObject;
        31. 365 }
          425 }
        1. 1 public static void main(String argv[]) {
        2. 2 try {
        3. 3 。。。
        4. 42 if (startSystemServer) {
        5. 43 startSystemServer(abiList, socketName);
        6. 44 }
        7. 45 。。。//然而并没有机会进入循环
          50 } catch (MethodAndArgsCaller caller) {
        8. 51 caller.run();
        9. 52 } catch (RuntimeException ex) {
        10. 53 Log.e(TAG, "Zygote died with exception", ex);
        11. 54 closeServerSocket();
        12. 55 throw ex;
        13. 56 }
        14. 57 }
      • 这个函数会执行两个操作,一个是调用zygoteInitNative函数来执行一个Binder进程间通信机制的初始化工作,这个工作完成之后,这个进 程中的Binder对象就可以方便地进行进程间通信了,另一个是调用上面传进来的com.android.server.SystemServer类的main函数。
    • 3.2 查看与验证Zygote启动systemserver
      • ps进程信息,验证system_server是Zygote的分裂出的第一个子进程.
    • 3.3 Zygote启动其他子进程
      • 注意:重复的不再涉及,我们只是分析一下7-12吧。
      • frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
        1. 1 /**
        2. 2 * Runs the zygote process's select loop. Accepts new connections as
        3. 3 * they happen, and reads commands from connections one spawn-request's
        4. 4 * worth at a time.
        5. 5 *
        6. 6 * @throws MethodAndArgsCaller in a child process when a main() should
        7. 7 * be executed.
        8. 8 */
        9. 9 private static void runSelectLoop(String abiList) throws MethodAndArgsCaller {
        10. 10 。。。
          18 while (true) {
        11. 19 。。。
        12. 38 try {
        13. 39 fdArray = fds.toArray(fdArray);
        14. 40 index = selectReadable(fdArray);
        15. 41 } catch (IOException ex) {
        16. 42 throw new RuntimeException("Error in select()", ex);
        17. 43 }
        18. 44
        19. 45 if (index < 0) {
        20. 46 throw new RuntimeException("Error in select()");
        21. 47 } else if (index == 0) {
        22. 48 ZygoteConnection newPeer = acceptCommandPeer(abiList);
        23. 49 peers.add(newPeer);
        24. 50 fds.add(newPeer.getFileDescriptor());
        25. 51 } else {
        26. 52 boolean done;
        27. 53 done = peers.get(index).runOnce();
        28. 54
        29. 55 if (done) {
        30. 56 peers.remove(index);
        31. 57 fds.remove(index);
        32. 58 }
        33. 59 }
        34. 60 }
        35. 61 }
      • runSelectLoopMode中while(true)循环,接收到Socket请求后,会fork出子进程,子进程调用handleChildProc方法,最终抛出RuntimeInit.invokeStaticMain异常,退出while(true)循环(与fork Systemserver不一样,后者没有进入循环),进入到android.app.ActivityThread类的main方法执行;父进程调用handleParentProc方法,再次进入runSelectLoopMode中while(true)循环,准备接收下一个的请求事件。
      • frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java
        1. 1 boolean runOnce() throws ZygoteInit.MethodAndArgsCaller {
        2.    ...
        3. 37 try {
        4. 38 ...
          105 pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
        5. 106 parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
        6. 107 parsedArgs.niceName, fdsToClose, parsedArgs.instructionSet,
        7. 108 parsedArgs.appDataDir);
        8. 109 checkTime(startTime, "zygoteConnection.runOnce: postForkAndSpecialize");
        9. 110 } catch (IOException ex) {
        10. 111 logAndPrintError(newStderr, "Exception creating pipe", ex);
        11. 112 } catch (ErrnoException ex) {
        12. 113 logAndPrintError(newStderr, "Exception creating pipe", ex);
        13. 114 } catch (IllegalArgumentException ex) {
        14. 115 logAndPrintError(newStderr, "Invalid zygote arguments", ex);
        15. 116 } catch (ZygoteSecurityException ex) {
        16. 117 logAndPrintError(newStderr,
        17. 118 "Zygote security policy prevents request: ", ex);
        18. 119 }
        19. 120
        20. 121 try {
        21. 122 if (pid == 0) {
        22. 123 // in child
        23. 124 IoUtils.closeQuietly(serverPipeFd);
        24. 125 serverPipeFd = null;
        25. 126 handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);
        26. 127
        27. 128 // should never get here, the child is expected to either
        28. 129 // throw ZygoteInit.MethodAndArgsCaller or exec().
        29. 130 return true;
        30. 131 } else {
        31. 132 // in parent...pid of < 0 means failure
        32. 133 IoUtils.closeQuietly(childPipeFd);
        33. 134 childPipeFd = null;
        34. 135 return handleParentProc(pid, descriptors, serverPipeFd, parsedArgs);
        35. 136 }
        36. 137 } finally {
        37. 138 IoUtils.closeQuietly(childPipeFd);
        38. 139 IoUtils.closeQuietly(serverPipeFd);
        39. 140 }
        40. 141 }
      • 10和11略过,只是返回而已。我们现在进入子进程的handleChildProc。
        1. 1 private void handleChildProc(Arguments parsedArgs,
        2. 2 FileDescriptor[] descriptors, FileDescriptor pipeFd, PrintStream newStderr)
        3. 3 throws ZygoteInit.MethodAndArgsCaller {
        4. 4
        5. 5 /**
        6. 6 * By the time we get here, the native code has closed the two actual Zygote
        7. 7 * socket connections, and substituted /dev/null in their place. The LocalSocket
        8. 8 * objects still need to be closed properly.
        9. 9 */
        10. 10
        11. 11 closeSocket();
        12. 12 ZygoteInit.closeServerSocket();
        13. 13
        14. 14 。。。
        15. 55 if (parsedArgs.invokeWith != null) {
        16. 56 WrapperInit.execStandalone(parsedArgs.invokeWith,
        17. 57 parsedArgs.classpath, className, mainArgs);
        18. 58 } else {
        19. 59 ClassLoader cloader;
        20. 60 if (parsedArgs.classpath != null) {
        21. 61 cloader = new PathClassLoader(parsedArgs.classpath,
        22. 62 ClassLoader.getSystemClassLoader());
        23. 63 } else {
        24. 64 cloader = ClassLoader.getSystemClassLoader();
        25. 65 }
        26. 66
        27. 67 try {
        28. 68 ZygoteInit.invokeStaticMain(cloader, className, mainArgs);
        29. 69 } catch (RuntimeException ex) {
        30. 70 logAndPrintError(newStderr, "Error starting.", ex);
        31. 71 }
        32. 72 }
        33. 73 。。。
        34. 74 }
      • 剩余的就和上面雷同了,这里不再分析。

4、总结

  • 系统启动时init进程会创建Zygote进程,Zygote进程负责后续Android应用程序框架层的其它进程的创建和启动工作。(可以使用ps查看)

    Zygote进程会首先创建一个SystemServer进程,SystemServer进程负责启动系统的关键服务,如包管理服务PackageManagerService和应用程序组件管理服务ActivityManagerService。

    当我们需要启动一个Android应用程序时,ActivityManagerService会通过Socket进程间通信机制,通知Zygote进程为这个应用程序创建一个新的进程。

 

Zygote启动及其作用的更多相关文章

  1. Android系统进程Zygote启动过程的源代码分析

    文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/6768304 在Android系统中,所有的应用 ...

  2. Android 8.1 源码_启动篇(二) -- 深入研究 zygote(转 Android 9.0 分析)

    前言 在Android中,zygote是整个系统创建新进程的核心进程.zygote进程在内部会先启动Dalvik虚拟机,继而加载一些必要的系统资源和系统类,最后进入一种监听状态.在之后的运作中,当其他 ...

  3. Zygote及System进程启动

    1.  init 根据init.rc 运行 app_process, 并携带‘--zygote' 和 ’--startSystemServer' 参数. 2.  AndroidRuntime.cpp: ...

  4. Android Zygote进程启动分析

    dvm,app进程,linux进程三者关系 DVM指 dalivk 的虚拟机.每一个 Android 应用程序都在它自己的进程中运行,都拥有一个独立的 Dalvik 虚拟机实例.而每一个 DVM 都是 ...

  5. 图解Android - Zygote, System Server 启动分析

    Init 是所有Linux程序的起点,而Zygote于Android,正如它的英文意思,是所有java程序的'孵化池'(玩过星际虫族的兄弟都晓得的).用ps 输出可以看到 >adb shell ...

  6. 笔记:Zygote和SystemServer进程启动过程

    简述 Android设备启动过程中,先是Linux内核加载完,接着Android中的第一个进程init启动,它会启动一些需要开机启动的进程. Zygote就是进程init启动起来的.Android中所 ...

  7. Android系统启动流程(二)解析Zygote进程启动过程

    1.Zygote简介 在Android系统中,DVM(Dalvik虚拟机).应用程序进程以及运行系统的关键服务的SystemServer进程都是由Zygote进程来创建的,我们也将它称为孵化器.它通过 ...

  8. Zygote和System进程的启动过程

    ##init脚本的启动 +------------+ +-------+ +-----------+ |Linux Kernel+--> |init.rc+-> |app_process| ...

  9. Zygote和System进程的启动过程、Android应用进程启动过程

    1.基本过程 init脚本的启动Zygote Zygote进程的启动 System进程的启动 Android应用进程启动过程 2.init脚本的启动 +------------+ +-------+ ...

随机推荐

  1. Chrome快捷键统计

    Chrome快捷键: Chrome 个人常用快捷键 1 将当前网页保存为书签 Ctrl + d 2 重新加载当前网页 Ctrl + r或F5 3 打开书签管理器 Ctrl + Shift + o 4 ...

  2. Android笔记(六十五) android中的动画——属性动画(propertyanimation)

    补间动画只能定义起始和结束两个帧在“透明度”.“旋转”.“倾斜”.“位移”4个方面的变化,逐帧动画也只能是播放多个图片,无法满足我们日常复杂的动画需求,所以谷歌在3.0开始,推出了属性动画(prope ...

  3. pandas数据处理

    首先,数据加载 pandas提供了一些用于将表格型数据读取为DataFrame对象的函数,期中read_csv和read_table这两个使用最多. 1.删除重复元素 使用duplicated()函数 ...

  4. helm笔记

    一.注意事项 1.values.yaml   中可以使用'#'号注释行,而/templates 下的文件不能用#号,如果要注释可以使用 {{/*  context  */}} 2.{{-    #忽略 ...

  5. K3 Cloud的数据中心加载异常处理

    以前一直是财务维护的K3  Cloud突然说不能登录,用的SQL 2008的数据库,运维也搞不定,找帮忙,因为是部署在阿里云上,上去看看数据库,这个K3数据库占了600多G,想看看这个表结构,就是打不 ...

  6. com.mysql.jdbc.Driver not loaded. Are you sure you've included the correct jdbc driver in :jdbc_driver_library?

    把对应的jdbc jar包放到 /usr/share/logstash/logstash-core/lib/jars/路径 下即可.可以在配置文件不用配置驱动库.

  7. 解决jdbc向数据库存入数据出现乱码的情况

    解决办法 1.修改项目的编码,建议统一使用utf-8来实现,这样整个项目就是utf-8. 2.jdbc:mysql://locathost:3306/数据库名称?useUnicode=true& ...

  8. EPL II 编程打印

    一.EPL II 格式及打印测试 注意N命令前的换行和最后P1后的换行.将此段代码复制到windows记事本里另存为Print.ext,文件名随便,后缀为ext.然后通过cmd控制命令行输入" ...

  9. JDK9的JShell简单使用

    JShell其实就是一个命令行工具,输入片段代码马上就可以看到结果,相当于脚本一行行解析执行,用户可以体验一把Java交互式编程环境.

  10. http和https 握手过程

    这几天测试打印机一直出现打印延迟或者不打印的BUG.找了几天也没有发现为啥没有打印或者打印延迟.然后今天公司的研发大佬过来找问题,并开个会,瞬间所有的问题都找出了并且知道怎么解决了.大佬果然还是大佬. ...