content: /*
   * Copyright (C) 2018 The Android Open Source Project
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  package com.android.internal.os;
  
  import android.app.LoadedApk;
  import android.app.ZygotePreload;
  import android.content.ComponentName;
  import android.content.pm.ApplicationInfo;
  import android.net.LocalSocket;
  import android.util.Log;
  
  import java.io.DataOutputStream;
  import java.io.IOException;
  import java.lang.reflect.Constructor;
  import java.lang.reflect.Method;
  
  /**
   * Startup class for an Application zygote process.
   *
   * See {@link ZygoteInit} for generic zygote startup documentation.
   *
   * @hide
   */
  class AppZygoteInit {
      public static final String TAG = "AppZygoteInit";
  
      private static ZygoteServer sServer;
  
      private static class AppZygoteServer extends ZygoteServer {
          @Override
          protected ZygoteConnection createNewConnection(LocalSocket socket, String abiList)
                  throws IOException {
              return new AppZygoteConnection(socket, abiList);
          }
      }
  
      private static class AppZygoteConnection extends ZygoteConnection {
          AppZygoteConnection(LocalSocket socket, String abiList) throws IOException {
              super(socket, abiList);
          }
  
          @Override
          protected void preload() {
              // Nothing to preload by default.
          }
  
          @Override
          protected boolean isPreloadComplete() {
              // App zygotes don't preload any classes or resources or defaults, all of their
              // preloading is package specific.
              return true;
          }
  
          @Override
          protected boolean canPreloadApp() {
              return true;
          }
  
          @Override
          protected void handlePreloadApp(ApplicationInfo appInfo) {
              Log.i(TAG, "Beginning application preload for " + appInfo.packageName);
              LoadedApk loadedApk = new LoadedApk(null, appInfo, null, null, false, true, false);
              ClassLoader loader = loadedApk.getClassLoader();
  
              Zygote.allowAppFilesAcrossFork(appInfo);
  
              if (appInfo.zygotePreloadName != null) {
                  Class<?> cl;
                  Method m;
                  try {
                      ComponentName preloadName = ComponentName.createRelative(appInfo.packageName,
                              appInfo.zygotePreloadName);
                      cl = Class.forName(preloadName.getClassName(), true, loader);
                      if (!ZygotePreload.class.isAssignableFrom(cl)) {
                          Log.e(TAG, preloadName.getClassName() + " does not implement "
                                  + ZygotePreload.class.getName());
                      } else {
                          Constructor<?> ctor = cl.getConstructor();
                          ZygotePreload preloadObject = (ZygotePreload) ctor.newInstance();
                          preloadObject.doPreload(appInfo);
                      }
                  } catch (ReflectiveOperationException e) {
                      Log.e(TAG, "AppZygote application preload failed for "
                              + appInfo.zygotePreloadName, e);
                  }
              } else {
                  Log.i(TAG, "No zygotePreloadName attribute specified.");
              }
  
              try {
                  DataOutputStream socketOut = getSocketOutputStream();
                  socketOut.writeInt(loader != null ? 1 : 0);
              } catch (IOException e) {
                  throw new IllegalStateException("Error writing to command socket", e);
              }
  
              Log.i(TAG, "Application preload done");
          }
      }
  
      public static void main(String[] argv) {
          AppZygoteServer server = new AppZygoteServer();
          ChildZygoteInit.runZygoteServer(server, argv);
      }
  }
  