Merge "Pass the targetSdkVersion through to the zygote-forked dalvik."
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 673b187..dbefb1f 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -266,7 +266,8 @@
      * @param uid The user-id under which the process will run.
      * @param gid The group-id under which the process will run.
      * @param gids Additional group-ids associated with the process.
-     * @param enableDebugger True if debugging should be enabled for this process.
+     * @param debugFlags Additional flags.
+     * @param targetSdkVersion The target SDK version for the app.
      * @param zygoteArgs Additional arguments to supply to the zygote process.
      * 
      * @return int If > 0 the pid of the new process; if 0 the process is
@@ -278,13 +279,13 @@
     public static final int start(final String processClass,
                                   final String niceName,
                                   int uid, int gid, int[] gids,
-                                  int debugFlags,
+                                  int debugFlags, int targetSdkVersion,
                                   String[] zygoteArgs)
     {
         if (supportsProcesses()) {
             try {
                 return startViaZygote(processClass, niceName, uid, gid, gids,
-                        debugFlags, zygoteArgs);
+                        debugFlags, targetSdkVersion, zygoteArgs);
             } catch (ZygoteStartFailedEx ex) {
                 Log.e(LOG_TAG,
                         "Starting VM process through Zygote failed");
@@ -316,9 +317,10 @@
      * {@hide}
      */
     public static final int start(String processClass, int uid, int gid,
-            int[] gids, int debugFlags, String[] zygoteArgs) {
+            int[] gids, int debugFlags, int targetSdkVersion,
+            String[] zygoteArgs) {
         return start(processClass, "", uid, gid, gids, 
-                debugFlags, zygoteArgs);
+                debugFlags, targetSdkVersion, zygoteArgs);
     }
 
     private static void invokeStaticMain(String className) {
@@ -500,7 +502,8 @@
      * @param gid a POSIX gid that the new process shuold setgid() to
      * @param gids null-ok; a list of supplementary group IDs that the
      * new process should setgroup() to.
-     * @param enableDebugger True if debugging should be enabled for this process.
+     * @param debugFlags Additional flags.
+     * @param targetSdkVersion The target SDK version for the app.
      * @param extraArgs Additional arguments to supply to the zygote process.
      * @return PID
      * @throws ZygoteStartFailedEx if process start failed for any reason
@@ -509,7 +512,7 @@
                                   final String niceName,
                                   final int uid, final int gid,
                                   final int[] gids,
-                                  int debugFlags,
+                                  int debugFlags, int targetSdkVersion,
                                   String[] extraArgs)
                                   throws ZygoteStartFailedEx {
         int pid;
@@ -537,6 +540,7 @@
             if ((debugFlags & Zygote.DEBUG_ENABLE_ASSERT) != 0) {
                 argsForZygote.add("--enable-assert");
             }
+            argsForZygote.add("--target-sdk-version=" + targetSdkVersion);
 
             //TODO optionally enable debuger
             //argsForZygote.add("--enable-debugger");
diff --git a/core/java/com/android/internal/os/RuntimeInit.java b/core/java/com/android/internal/os/RuntimeInit.java
index f13e770..53516c0 100644
--- a/core/java/com/android/internal/os/RuntimeInit.java
+++ b/core/java/com/android/internal/os/RuntimeInit.java
@@ -252,9 +252,10 @@
      *   <li> <code> [--] &lt;start class name&gt;  &lt;args&gt;
      * </ul>
      *
+     * @param targetSdkVersion target SDK version
      * @param argv arg strings
      */
-    public static final void zygoteInit(String[] argv)
+    public static final void zygoteInit(int targetSdkVersion, String[] argv)
             throws ZygoteInit.MethodAndArgsCaller {
         if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application from zygote");
 
@@ -263,7 +264,7 @@
         commonInit();
         zygoteInitNative();
 
-        applicationInit(argv);
+        applicationInit(targetSdkVersion, argv);
     }
 
     /**
@@ -274,20 +275,22 @@
      * which calls {@link WrapperInit#main} which then calls this method.
      * So we don't need to call commonInit() here.
      *
+     * @param targetSdkVersion target SDK version
      * @param argv arg strings
      */
-    public static void wrapperInit(String[] argv)
+    public static void wrapperInit(int targetSdkVersion, String[] argv)
             throws ZygoteInit.MethodAndArgsCaller {
         if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application from wrapper");
 
-        applicationInit(argv);
+        applicationInit(targetSdkVersion, argv);
     }
 
-    private static void applicationInit(String[] argv)
+    private static void applicationInit(int targetSdkVersion, String[] argv)
             throws ZygoteInit.MethodAndArgsCaller {
         // We want to be fairly aggressive about heap utilization, to avoid
         // holding on to a lot of memory that isn't needed.
         VMRuntime.getRuntime().setTargetHeapUtilization(0.75f);
+        VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion);
 
         final Arguments args;
         try {
diff --git a/core/java/com/android/internal/os/WrapperInit.java b/core/java/com/android/internal/os/WrapperInit.java
index 860a08c..c6b3e7c 100644
--- a/core/java/com/android/internal/os/WrapperInit.java
+++ b/core/java/com/android/internal/os/WrapperInit.java
@@ -47,16 +47,22 @@
      * wrapper process instead of by forking Zygote.
      *
      * The first argument specifies the file descriptor for a pipe that should receive
-     * the pid of this process, or 0 if none.  The remaining arguments are passed to
-     * the runtime.
+     * the pid of this process, or 0 if none.
+     *
+     * The second argument is the target SDK version for the app.
+     *
+     * The remaining arguments are passed to the runtime.
      *
      * @param args The command-line arguments.
      */
     public static void main(String[] args) {
         try {
+            // Parse our mandatory arguments.
+            int fdNum = Integer.parseInt(args[0], 10);
+            int targetSdkVersion = Integer.parseInt(args[1], 10);
+
             // Tell the Zygote what our actual PID is (since it only knows about the
             // wrapper that it directly forked).
-            int fdNum = Integer.parseInt(args[0], 10);
             if (fdNum != 0) {
                 try {
                     FileDescriptor fd = ZygoteInit.createFileDescriptor(fdNum);
@@ -73,9 +79,9 @@
             ZygoteInit.preload();
 
             // Launch the application.
-            String[] runtimeArgs = new String[args.length - 1];
-            System.arraycopy(args, 1, runtimeArgs, 0, runtimeArgs.length);
-            RuntimeInit.wrapperInit(runtimeArgs);
+            String[] runtimeArgs = new String[args.length - 2];
+            System.arraycopy(args, 2, runtimeArgs, 0, runtimeArgs.length);
+            RuntimeInit.wrapperInit(targetSdkVersion, runtimeArgs);
         } catch (ZygoteInit.MethodAndArgsCaller caller) {
             caller.run();
         }
@@ -87,11 +93,12 @@
      *
      * @param invokeWith The wrapper command.
      * @param niceName The nice name for the application, or null if none.
+     * @param targetSdkVersion The target SDK version for the app.
      * @param pipeFd The pipe to which the application's pid should be written, or null if none.
      * @param args Arguments for {@link RuntimeInit.main}.
      */
     public static void execApplication(String invokeWith, String niceName,
-            FileDescriptor pipeFd, String[] args) {
+            int targetSdkVersion, FileDescriptor pipeFd, String[] args) {
         StringBuilder command = new StringBuilder(invokeWith);
         command.append(" /system/bin/app_process /system/bin --application");
         if (niceName != null) {
@@ -99,6 +106,8 @@
         }
         command.append(" com.android.internal.os.WrapperInit ");
         command.append(pipeFd != null ? pipeFd.getInt$() : 0);
+        command.append(' ');
+        command.append(targetSdkVersion);
         Zygote.appendQuotedShellArgs(command, args);
         Zygote.execShell(command.toString());
     }
diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
index 7cb002c..fcac2ac 100644
--- a/core/java/com/android/internal/os/ZygoteConnection.java
+++ b/core/java/com/android/internal/os/ZygoteConnection.java
@@ -18,6 +18,7 @@
 
 import android.net.Credentials;
 import android.net.LocalSocket;
+import android.os.Build;
 import android.os.Process;
 import android.os.SystemProperties;
 import android.util.Log;
@@ -333,6 +334,10 @@
          */
         int debugFlags;
 
+        /** from --target-sdk-version. */
+        int targetSdkVersion;
+        boolean targetSdkVersionSpecified;
+
         /** from --classpath */
         String classpath;
 
@@ -402,6 +407,14 @@
                     gidSpecified = true;
                     gid = Integer.parseInt(
                             arg.substring(arg.indexOf('=') + 1));
+                } else if (arg.startsWith("--target-sdk-version=")) {
+                    if (targetSdkVersionSpecified) {
+                        throw new IllegalArgumentException(
+                                "Duplicate target-sdk-version specified");
+                    }
+                    targetSdkVersionSpecified = true;
+                    targetSdkVersion = Integer.parseInt(
+                            arg.substring(arg.indexOf('=') + 1));
                 } else if (arg.equals("--enable-debugger")) {
                     debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER;
                 } else if (arg.equals("--enable-safemode")) {
@@ -505,6 +518,10 @@
                         "--runtime-init and -classpath are incompatible");
             }
 
+            if (!targetSdkVersionSpecified) {
+                targetSdkVersion = Build.VERSION.SDK_INT;
+            }
+
             remainingArgs = new String[args.length - curArg];
 
             System.arraycopy(args, curArg, remainingArgs, 0,
@@ -821,9 +838,11 @@
         if (parsedArgs.runtimeInit) {
             if (parsedArgs.invokeWith != null) {
                 WrapperInit.execApplication(parsedArgs.invokeWith,
-                        parsedArgs.niceName, pipeFd, parsedArgs.remainingArgs);
+                        parsedArgs.niceName, parsedArgs.targetSdkVersion,
+                        pipeFd, parsedArgs.remainingArgs);
             } else {
-                RuntimeInit.zygoteInit(parsedArgs.remainingArgs);
+                RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion,
+                        parsedArgs.remainingArgs);
             }
         } else {
             String className;
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index b4a7e52..6ec186d 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -48,7 +48,7 @@
  * Startup class for the zygote process.
  *
  * Pre-initializes some classes, and then waits for commands on a UNIX domain
- * socket. Based on these commands, forks of child processes that inherit
+ * socket. Based on these commands, forks off child processes that inherit
  * the initial state of the VM.
  *
  * Please see {@link ZygoteConnection.Arguments} for documentation on the
@@ -453,12 +453,13 @@
 
         if (parsedArgs.invokeWith != null) {
             WrapperInit.execApplication(parsedArgs.invokeWith,
-                    parsedArgs.niceName, null, parsedArgs.remainingArgs);
+                    parsedArgs.niceName, parsedArgs.targetSdkVersion,
+                    null, parsedArgs.remainingArgs);
         } else {
             /*
              * Pass the remaining arguments to SystemServer.
              */
-            RuntimeInit.zygoteInit(parsedArgs.remainingArgs);
+            RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs);
         }
 
         /* should never reach here */
@@ -491,7 +492,9 @@
             /* Request to fork the system server process */
             pid = Zygote.forkSystemServer(
                     parsedArgs.uid, parsedArgs.gid,
-                    parsedArgs.gids, parsedArgs.debugFlags, null,
+                    parsedArgs.gids,
+                    parsedArgs.debugFlags,
+                    null,
                     parsedArgs.permittedCapabilities,
                     parsedArgs.effectiveCapabilities);
         } catch (IllegalArgumentException ex) {
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 29cccb6..62f0fea 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -1960,7 +1960,8 @@
                 debugFlags |= Zygote.DEBUG_ENABLE_ASSERT;
             }
             int pid = Process.start("android.app.ActivityThread",
-                    app.processName, uid, uid, gids, debugFlags, null);
+                    app.processName, uid, uid, gids, debugFlags,
+                    app.info.targetSdkVersion, null);
             BatteryStatsImpl bs = app.batteryStats.getBatteryStats();
             synchronized (bs) {
                 if (bs.isOnBattery()) {