Android 系统源码——打包APK安装过程、应用进程启动过程

版权声明:本文为博主csdn_aiyang原创文章,未经博主允许不得转载。 https://blog.csdn.net/csdn_aiyang/article/details/82462399

一、Android APK的构建过程

通过IDE可以生成可以在android设备中安装的apk文件,Google官方提供的构建APK的过程流程图如下:

  • 打包APK流程总结如下:
  1. AAPT(Android Asset Packaging Tool)工具会打包应用中的资源文件,如AndroidManifest.xml、layout布局中的xml等,并将xml文件编译为二进制形式,当然assets文件夹中的文件不会被编译,图片及raw文件夹中的资源也会保持原来的形态,需要注意的是raw文件夹中的资源也会生成资源id。AAPT编译完成之后会生成R.java文件。
  2. AIDL工具会将所有的aidl接口转化为java接口。
  3. 所有的java代码,包括R.java与aidl文件都会被Java编译器编译成.class文件。
  4. Dex工具会将上述产生的.class文件及第三库及其他.class文件编译成.dex文件(dex文件是Dalvik虚拟机可以执行的格式),dex文件最终会被打包进APK文件。
  5. ApkBuilder工具会将编译过的资源及未编译过的资源(如图片等)以及.dex文件打包成APK文件。
  6. 生成APK文件后,需要对其签名才可安装到设备,平时测试时会使用debug keystore,当正式发布应用时必须使用release版的keystore对应用进行签名。
  7. 如果对APK正式签名,还需要使用zipalign工具对APK进行对齐操作,这样做的好处是当应用运行时会提高速度,但是相应的会增加内存的开销。

我们知道,通过Intent就可以执行APK安装的,执行如下代码后,我们就会打开安装apk文件的程序并执行安装逻辑了,大家应该都知道这段代码执行的结果是打开一个隐式的Activity,即PackageInstallerActivity。

Intent intent = new Intent(Intent.ACTION_VIEW);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setDataAndType(Uri.parse("file://" + path),"application/vnd.android.package-archive");
context.startActivity(intent);
  • 安装APK流程总结如下:
  1. 代码中执行intent.setDataAndType(Uri.parse(“file://” + path),”application/vnd.android.package-archive”);可以打开隐士的PackageInstallerActivity。
  2. PackageInstallerActivity主要用于执行解析apk文件;解析manifest.xml、解析签名等操作。
  3. 点击安装按钮,调起InstallAppProcess,这个Activity主要用于执行安装apk逻辑,用于初始化安装界面,用于初始化用户UI;并调用PackageInstaller执行安装逻辑。
  4. InstallAppProcess内注册有广播,当安装完成之后接收广播,更新UI。显示apk安装完成界面。

二、Android 应用进程启动过程

    首先,Android在系统架构分为四个层面。从高层到低层分别是应用程序层、应用程序框架层、系统运行库层和linux核心层。另外,进程是系统的执行单位。Linux系统是核心底层,那么Android的其他进程都是基于Linux进程的根进程init进程,因此它可以算作是整个android操作系统的第一个进程。最后,我们知道android系统的Zygote进程是所有的android进程的父进程,包括SystemServer和各种应用进程都是通过Zygote进程fork出来的。而Zygote进程则是通过linux系统的init进程启动的,也就是说,android系统中各种进程的启动方式及顺序是:

init进程 –> Zygote进程 –> SystemServer进程 –>各种应用进程

各种应用进程:启动自己编写的客户端应用时,一般都是重新启动一个应用进程,有自己的虚拟机与运行环境;

init进程在启动Zygote进程时一般都会调用ZygoteInit类的main方法,Zygote进程mian方法主要执行逻辑:

  • 初始化DDMS;

  • 注册Zygote进程的socket通讯;

  • 初始化Zygote中的各种类,资源文件,OpenGL,类库,Text资源等等;

  • 初始化完成之后fork出SystemServer进程;

  • fork出SystemServer进程之后,关闭socket连接;

其实,SystemServer进程主要的作用是启动各种系统服务,比如ActivityManagerService,PackageManagerService,WindowManagerService等服务。我们平时熟知的各种系统性的服务其实都是在SystemServer进程中启动的,而当我们的应用需要使用各种系统服务的时候,其实也是通过与SystemServer进程通讯获取各种服务对象的句柄来执行相应的操作。

  • SystemServer进程启动服务的启动函数为main函数;

  • SystemServer在执行过程中首先会初始化一些系统变量,加载类库,创建Context对象,创建SystemServiceManager对象等之后才开始启动系统服务;

  • SystemServer进程将系统服务分为三类:boot服务,core服务和other服务,并逐步启动;

  • SystemServer进程在尝试启动服务之前会首先尝试与Zygote建立socket通讯,只有通讯成功之后才会开始尝试启动服务;

  • 创建的系统服务过程中主要通过SystemServiceManager对象来管理,通过调用服务对象的构造方法和onStart方法初始化服务的相关变量;

  • 服务对象都有自己的异步消息对象,并运行在单独的线程中;

其实,我们知道SystemServer进程主要用于启动系统的各种服务,而且其中就包含负责启动Launcher程序的服务-LauncherAppService。Launcher 程序就是我们平时看到的桌面程序,它其实也是一个android应用程序,只不过这个应用程序是系统默认第一个启动的应用程序,这里我们就简单的分析一下Launcher应用的启动流程。

前面说SystemServer调用三个内部方法分别启动boot service、core service和other service。在调用startOtherService方法中就会通过调用mActivityManagerService.systemReady()方法。

public void systemReady(final Runnable goingCallback) {
        ...
        // Start up initial activity.
        mBooting = true;
        startHomeActivityLocked(mCurrentUserId, "systemReady");
        ...
    }

这个方法体中调用了startHomeActivityLocked方法,看名字就知道开始执行启动homeActivity的操作。好了,既然如此,我们再看一下startHomeActivityLocked的具体实现:

boolean startHomeActivityLocked(int userId, String reason) {
        if (mFactoryTest == FactoryTest.FACTORY_TEST_LOW_LEVEL
                && mTopAction == null) {
            return false;
        }
        Intent intent = getHomeIntent();//下面第一段代码进入查看
        ActivityInfo aInfo =
            resolveActivityInfo(intent, STOCK_PM_FLAGS, userId);
        if (aInfo != null) {
            intent.setComponent(new ComponentName(
                    aInfo.applicationInfo.packageName, aInfo.name));
            aInfo = new ActivityInfo(aInfo);
            aInfo.applicationInfo = getAppInfoForUser(aInfo.applicationInfo, userId);
            ProcessRecord app = getProcessRecordLocked(aInfo.processName,
                    aInfo.applicationInfo.uid, true);
            if (app == null || app.instrumentationClass == null) {
                intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
                mStackSupervisor.startHomeActivity(intent, aInfo, reason);//第二段代码查看
            }
        }

        return true;
    }
Intent getHomeIntent() {
        Intent intent = new Intent(mTopAction, mTopData != null ? Uri.parse(mTopData) : null);
        intent.setComponent(mTopComponent);
        if (mFactoryTest != FactoryTest.FACTORY_TEST_LOW_LEVEL) {
            intent.addCategory(Intent.CATEGORY_HOME);
        }
        return intent;
    }

可以发现,Intent是一个隐士对象,并且添加了Intent.CATEGORY_HOME常量,这个其实是一个launcher的标志,一般系统的启动页面Activity都会在androidmanifest.xml中配置这个标志。

void startHomeActivity(Intent intent, ActivityInfo aInfo, String reason) {
        moveHomeStackTaskToTop(HOME_ACTIVITY_TYPE, reason);
        startActivityLocked(null /* caller */, intent, null /* resolvedType */, aInfo,
                null /* voiceSession */, null /* voiceInteractor */, null /* resultTo */,
                null /* resultWho */, 0 /* requestCode */, 0 /* callingPid */, 0 /* callingUid */,
                null /* callingPackage */, 0 /* realCallingPid */, 0 /* realCallingUid */,
                0 /* startFlags */, null /* options */, false /* ignoreTargetSecurity */,
                false /* componentSpecified */,
                null /* outActivity */, null /* container */,  null /* inTask */);
        if (inResumeTopActivity) {

            scheduleResumeTopActivities();

        }
    }

发现其调用的是scheduleResumeTopActivities()方法,这个方法其实是关于Activity的启动流程的逻辑的,这逻辑后面会讲。因为我们的Launcher启动的Intent是一个隐士的Intent,所以我们会启动在androidmanifest.xml中配置了相同catogory的activity,androidManifest中配置的这个catogory其实就是LauncherActivity。

LauncherActivity继承与ListActivity,我们先看一下其Layout布局文件和onCreate方法:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    >

    <ListView
        android:id="@android:id/list"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        />

    <TextView
        android:id="@android:id/empty"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        android:text="@string/activity_list_empty"
        android:visibility="gone"
        android:textAppearance="?android:attr/textAppearanceMedium"
        />

</FrameLayout>
@Override
protected void onCreate(Bundle icicle) {
        super.onCreate(icicle);

        mPackageManager = getPackageManager();
        if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_WATCH)) {
            requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
            setProgressBarIndeterminateVisibility(true);
        }
        onSetContentView();
        mIconResizer = new IconResizer();

        mIntent = new Intent(getTargetIntent());
        mIntent.setComponent(null);
        mAdapter = new ActivityAdapter(mIconResizer);

        setListAdapter(mAdapter);
        getListView().setTextFilterEnabled(true);

        updateAlertTitle();
        updateButtonText();

        if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_WATCH)) {
            setProgressBarIndeterminateVisibility(false);
        }
    }

可见,手机桌面其实就是一个ListView控件,在onCreate方法中初始化了一个PackageManager,从中查询出系统所有已经安装的应用列表,包括应用包名、图标等信息,然后将这些信息以Adapter方式注入到Listview中将系统应用图标和名称显示出来。 另外,在系统的回调方法onListItemClick中说明了,为什么我们点击某一个应用图标之后就可以启动某一项应用的原因了。

@Override
protected void onListItemClick(ListView l, View v, int position, long id) {
        Intent intent = intentForPosition(position);
        startActivity(intent);
}
protected Intent intentForPosition(int position) {
        ActivityAdapter adapter = (ActivityAdapter) mAdapter;
        return adapter.intentForPosition(position);
}
public Intent intentForPosition(int position) {
            if (mActivitiesList == null) {
                return null;
            }

            Intent intent = new Intent(mIntent);
            ListItem item = mActivitiesList.get(position);
            intent.setClassName(item.packageName, item.className);
            if (item.extras != null) {
                intent.putExtras(item.extras);
            }
            return intent;
}

    所以,LauncherActivity中是以ListView来显示我们的应用图标列表的,并且为每个Item保存了应用的包名和启动Activity类名,这样点击某一项应用图标的时候就可以根据应用包名和启动Activity名称启动我们的App了。

    其实Android中应用进程可以通过许多方式启动,比如启动一个Activity、Service、ContentProvider或BroadcastReceiver,也就是说通过启动四大组件的方式启动,这时候系统会判断当前这些组件所需要的应用进程是否已经启动,若没有的话,则会启动应用进程。通过上面Launcher启动流程,我们知道每一个launcher中的图标对应着一个应用报名和启动activity类名,查看LauncherActivity中的图标点击事件:

protected void onListItemClick(ListView l, View v, int position, long id) {
        Intent intent = intentForPosition(position);
        startActivity(intent);
}

这里调用了startActivity方法传入Intentd对象来启动这个activity。很明显,当前该应用属于冷启动,也就是说我们调用的startActivity方法不单单为我们启动了这个activity,也同时在启动activity之前启动了这个应用进程。好了,那我们这里就以这个方法为入口分析一下应用进程的启动流程。

@Override
public void startActivity(Intent intent) {
        this.startActivity(intent, null);
}

发现其调用的startActivity的重载方法,传入Intent对象和可为空Bundle对象。 并且发现继续调用startActivityForResult方法。

@Override
    public void startActivity(Intent intent, @Nullable Bundle options) {
        if (options != null) {
            startActivityForResult(intent, -1, options);
        } else {
            startActivityForResult(intent, -1);
        }
    }

很明显的此时传递的options为空,继续跟进:

public void startActivityForResult(Intent intent, int requestCode) {
        startActivityForResult(intent, requestCode, null);
}

好吧,最后调用的还是startActivityForResult(intent, requestCode, null)这个重载方法:

public void startActivityForResult(Intent intent, int requestCode, @Nullable Bundle options) {
        if (mParent == null) {
            Instrumentation.ActivityResult ar = mInstrumentation.execStartActivity(
                    this, mMainThread.getApplicationThread(), mToken, this,intent, requestCode, options);
            if (ar != null) {
                mMainThread.sendActivityResult(
                    mToken, mEmbeddedID, requestCode, ar.getResultCode(),ar.getResultData());
            }
            if (requestCode >= 0) {
                mStartedActivity = true;
            }

            cancelInputsAndStartExitTransition(options);
       
        } else {
            if (options != null) {
                mParent.startActivityFromChild(this, intent, requestCode, options);
            } else {
                mParent.startActivityFromChild(this, intent, requestCode);
            }
        }
    }

首先注意mInstrumentation.execStartActivity方法。Instrumentation对象,他是Android系统中应用程序端操作Activity的具体操作类,这里的操作是相对于ActivityManagerService服务端来说的。也就是说当我们在执行对Activity的具体操作时,比如回调生命周期的各个方法都是借助于Instrumentation类来实现的。看一下源码:

public ActivityResult execStartActivity(
            Context who, IBinder contextThread, IBinder token, Activity target,
            Intent intent, int requestCode, Bundle options) {
        ...
        try {
            intent.migrateExtraStreamToClipData();
            intent.prepareToLeaveProcess();
//关键代码
            int result = ActivityManagerNative.getDefault()
                .startActivity(whoThread, who.getBasePackageName(), intent,
                        intent.resolveTypeIfNeeded(who.getContentResolver()),
                        token, target != null ? target.mEmbeddedID : null,
                        requestCode, 0, null, options);
            checkStartActivityResult(result, intent);
        } catch (RemoteException e) {
            throw new RuntimeException("Failure from system", e);
        }
        return null;
    }

关键代码段实际上是进程间通讯。ActivityManagerNative继承于Binder接口,本身就是一个Binder对象,然后上面我们介绍SystemServer进程的时候对ActivityManagerService有过了解,发现其继承于ActivityManagerNative,好吧,了解过Binder机制的知道,ActivityManagerService就是这个Binder机制的服务器端而ActivityManagerNative就是这个Binder机制的客户端。所以我们这里调用的startActivity实际上是将参数传递给ActivityManagerService,并执行ActivityManagerService的startActivity方法。

既然这样,我们看一下ActivityManagerService的startActivity方法:

@Override
    public final int startActivity(IApplicationThread caller, String callingPackage,
            Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
            int startFlags, ProfilerInfo profilerInfo, Bundle options) {
        return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,
            resultWho, requestCode, startFlags, profilerInfo, options,
            UserHandle.getCallingUserId());
    }

然后我们继续看一下startActivityAsUser方法:

@Override
    public final int startActivityAsUser(IApplicationThread caller, String callingPackage,
            Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
            int startFlags, ProfilerInfo profilerInfo, Bundle options, int userId) {
        enforceNotIsolatedCaller("startActivity");
        userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId,
                false, ALLOW_FULL_ONLY, "startActivity", null);

        return mStackSupervisor.startActivityMayWait(caller, -1, callingPackage, intent,
                resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
                profilerInfo, null, null, options, false, userId, null, null);
    }

继续查看startActivityMayWait方法:

final int startActivityMayWait(IApplicationThread caller, int callingUid,
            String callingPackage, Intent intent, String resolvedType,
            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
            IBinder resultTo, String resultWho, int requestCode, int startFlags,
            ProfilerInfo profilerInfo, WaitResult outResult, Configuration config,
            Bundle options, boolean ignoreTargetSecurity, int userId,
            IActivityContainer iContainer, TaskRecord inTask) {
        ...

            int res = startActivityLocked(caller, intent, resolvedType, aInfo,
                    voiceSession, voiceInteractor, resultTo, resultWho,
                    requestCode, callingPid, callingUid, callingPackage,
                    realCallingPid, realCallingUid, startFlags, options, ignoreTargetSecurity,
                    componentSpecified, null, container, inTask);

            ...

            return res;
        }
    }

这里调用了startActivityLocked方法,也就是说在初始化其他逻辑之后,这个方法会调用startActivityLocked方法,然后我们查看startActivityLocked方法发现其调用了resumeTopActivitiesLocked方法:

if (doResume) {
            mStackSupervisor.resumeTopActivitiesLocked(this, r, options);
}

继续跟进:

final boolean resumeTopActivityLocked(ActivityRecord prev) {
        return resumeTopActivityLocked(prev, null);
    }

resumeTopActivityLocked方法中又调用了resumeTopActivityInnerLocked方法,resumeTopActivityInnerLocked方法中又调用了startSpecificActivityLocked方法:

final ProcessRecord startProcessLocked(String processName,
            ApplicationInfo info, boolean knownToBeDead, int intentFlags,
            String hostingType, ComponentName hostingName, boolean allowWhileBooting,
            boolean isolated, boolean keepIfLarge) {
        return startProcessLocked(processName, info, knownToBeDead, intentFlags, hostingType,
                hostingName, allowWhileBooting, isolated, 0 /* isolatedUid */, keepIfLarge,
                null /* ABI override */, null /* entryPoint */, null /* entryPointArgs */,
                null /* crashHandler */);
    }

查看startProcessLocked方法的具体实现:

checkTime(startTime, "startProcess: asking zygote to start proc");
            Process.ProcessStartResult startResult = Process.start(entryPoint,
                    app.processName, uid, uid, gids, debugFlags, mountExternal,
                    app.info.targetSdkVersion, app.info.seinfo, requiredAbi, instructionSet,
                    app.info.dataDir, entryPointArgs);
            checkTime(startTime, "startProcess: returned from zygote!");

查看关键代码,这里调用了Process.start方法:

public static final ProcessStartResult start(final String processClass,
                                  final String niceName,
                                  int uid, int gid, int[] gids,
                                  int debugFlags, int mountExternal,
                                  int targetSdkVersion,
                                  String seInfo,
                                  String abi,
                                  String instructionSet,
                                  String appDataDir,
                                  String[] zygoteArgs) {
        try {
            return startViaZygote(processClass, niceName, uid, gid, gids,
                    debugFlags, mountExternal, targetSdkVersion, seInfo,
                    abi, instructionSet, appDataDir, zygoteArgs);
        } catch (ZygoteStartFailedEx ex) {
            Log.e(LOG_TAG,
                    "Starting VM process through Zygote failed");
            throw new RuntimeException(
                    "Starting VM process through Zygote failed", ex);
        }
    }

最后,这里的processClass就是要启动的进程的名称,这里传递的就是ActivityThread:"android.app.ActivityThread"。具体的Process启动进程的Native层代码这里不做过多的分析,这个方法就是启动了AcitivtyThread进程并执行了ActivityThread的main方法,所以我们经常说的进程的启动方法就是ActivityThread的main方法,就在这里实现的。

猜你喜欢

转载自blog.csdn.net/csdn_aiyang/article/details/82462399