App启动——Application的创建

Application的创建

一个 app 启动时候创建一个 Application 对象。这个对象的创建时间在 frameworks 中调用创建的,创建流程可见下图,涉及的几个主要的类调用。

Application创建流程

一、主线程运行入口

​ APP进程起来后,主线程运行入库 ActivityThread.main() 方法。

    ```java
    // ActivityThread.java
    
    @UnsupportedAppUsage
    final ApplicationThread mAppThread = new ApplicationThread();
    
    public static void main(String[] args) {
    	// ...
        ActivityThread thread = new ActivityThread();
        thread.attach(false, startSeq);
        // ...
    }
    
    @UnsupportedAppUsage
    private void attach(boolean system, long startSeq) {
        // ...
    
        if (!system) {
            // ...
    
            final IActivityManager mgr = ActivityManager.getService(); //获取 IActivityManager 对象。
            try {
                mgr.attachApplication(mAppThread, startSeq); // Binder 调用 AMS 的 attachApplicaion() 方法。
            } catch (RemoteException ex) {
                throw ex.rethrowFromSystemServer();
            }
    		// ...
        }
    
        // ...
    }
    ```

运行启动是一般的app,并非 system app,因此进入到 if 分支。

二、ActivityManagerService 方法执行

从app主线程执行,进而跨进程调用到 ActivityManagerServiceattachApplication(IApplicationThread thread, long startSeq) 方法。

// ActivityManagerService.java
@Override
public final void attachApplication(IApplicationThread thread, long startSeq) {
    if (thread == null) {
        throw new SecurityException("Invalid application interface");
    }
    synchronized (this) {
        int callingPid = Binder.getCallingPid();
        final int callingUid = Binder.getCallingUid();
        final long origId = Binder.clearCallingIdentity();
        attachApplicationLocked(thread, callingPid, callingUid, startSeq);
        Binder.restoreCallingIdentity(origId);
    }
}

@GuardedBy("this")
private void attachApplicationLocked(@NonNull IApplicationThread thread,
        int pid, int callingUid, long startSeq) {
	// ......  这里的一个比较重要的数据是 appInfo:ApplicationInfo
    // if 分支内,表明运行的时候隔离状态的app,这样的app不能访问系统资源,服务及其他app进程。
    if (app.getIsolatedEntryPoint() != null) {
        // This is an isolated process which should just call an entry point instead of
        // being bound to an application.
        thread.runIsolatedEntryPoint(
                app.getIsolatedEntryPoint(), app.getIsolatedEntryPointArgs());
    } else if (instr2 != null) {
        thread.bindApplication(processName, appInfo,
                app.sdkSandboxClientAppVolumeUuid, app.sdkSandboxClientAppPackage,
                providerList,
                instr2.mClass,
                profilerInfo, instr2.mArguments,
                instr2.mWatcher,
                instr2.mUiAutomationConnection, testMode,
                mBinderTransactionTrackingEnabled, enableTrackAllocation,
                isRestrictedBackupMode || !normalMode, app.isPersistent(),
                new Configuration(app.getWindowProcessController().getConfiguration()),
                app.getCompat(), getCommonServicesLocked(app.isolated),
                mCoreSettingsObserver.getCoreSettingsLocked(),
                buildSerial, autofillOptions, contentCaptureOptions,
                app.getDisabledCompatChanges(), serializedSystemFontMap,
                app.getStartElapsedTime(), app.getStartUptime());
    } else {
        thread.bindApplication(processName, appInfo,
                app.sdkSandboxClientAppVolumeUuid, app.sdkSandboxClientAppPackage,
                providerList, null, profilerInfo, null, null, null, testMode,
                mBinderTransactionTrackingEnabled, enableTrackAllocation,
                isRestrictedBackupMode || !normalMode, app.isPersistent(),
                new Configuration(app.getWindowProcessController().getConfiguration()),
                app.getCompat(), getCommonServicesLocked(app.isolated),
                mCoreSettingsObserver.getCoreSettingsLocked(),
                buildSerial, autofillOptions, contentCaptureOptions,
                app.getDisabledCompatChanges(), serializedSystemFontMap,
                app.getStartElapsedTime(), app.getStartUptime());
    }
	// ......
}

在内部调用到 attachApplicationLocked() 方法,在方法内部,会执行到 bindApplication() 方法,除非运行的app是一个独立APP,即不访问系统任何资源。这个方法里还有一个重要的数据变量是 appInfo 表示了应用的信息,会在调用 bindApplication() 方法时传递给 ApplicationThread 对象方法。

三、ApplicationThread.bindApplication()

// ActivityThread.java

private class ApplicationThread extends IApplicationThread.Stub {
    @Override
    public final void bindApplication(String processName, ApplicationInfo appInfo,
            String sdkSandboxClientAppVolumeUuid, String sdkSandboxClientAppPackage,
            ProviderInfoList providerList, ComponentName instrumentationName,
            ProfilerInfo profilerInfo, Bundle instrumentationArgs,
            IInstrumentationWatcher instrumentationWatcher,
            IUiAutomationConnection instrumentationUiConnection, int debugMode,
            boolean enableBinderTracking, boolean trackAllocation,
            boolean isRestrictedBackupMode, boolean persistent, Configuration config,
            CompatibilityInfo compatInfo, Map services, Bundle coreSettings,
            String buildSerial, AutofillOptions autofillOptions,
            ContentCaptureOptions contentCaptureOptions, long[] disabledCompatChanges,
            SharedMemory serializedSystemFontMap,
            long startRequestedElapsedTime, long startRequestedUptime) {
        // ......
        
            AppBindData data = new AppBindData();
            // 构建 AppBindData 数据结构。
            updateCompatOverrideScale(compatInfo);
            CompatibilityInfo.applyOverrideScaleIfNeeded(config);
            sendMessage(H.BIND_APPLICATION, data);  // 发送消息。
    }
}

ActivityManagerService 中进行执行后,获取必要的信息,然后执行回到 ApplicationThread 的 app 进程 bindApplication() 方法中,并构建 AppBindData 数据对象,最终发送消息 H.BIND_APPLICATION 进入消息队列等待执行。

四、handleBindApplication(AppBindData data)

通过消息机制执行到 handleMessage(Message msg),依据消息 whatBIND_APPLICATION 执行方法 handleBindApplication(AppBindData data)

// ActivityThread.java

@UnsupportedAppUsage
private void handleBindApplication(AppBindData data) {
	// ...
    // 获取 LoadedApk 类型对象 
    data.info = getPackageInfo(data.appInfo, mCompatibilityInfo, null /* baseLoader */,  
    							false /* securityViolation */, true /* includeCode */,
    							false /* registerPackage */, isSdkSandbox);
    
    // ...
    // 获取 ActivityManagerService 的 Binder 句柄
    final IActivityManager mgr = ActivityManager.getService();   
    // 创建 Context 上下文对象
    final ContextImpl appContext = ContextImpl.createAppContext(this, data.info);    
    
    // ...
    Application app;
    // ...
        try {
			// 通过 LoadedApk 对象创建 Application 对象,内部具体实现细节,并且调用到了 Application.attach(Coext)。
		    // 在 attach(Context) 方法内调用从 ContextWrapper 继承而来的 attachBaseContext(Context),设置 mBaseContext 的实例变量。 
            app = data.info.makeApplicationInner(data.restrictedBackupMode, null);
            // ...
        } finally {
            // ...
        }
		// ...
        try {
            mgr.finishAttachApplication(mStartSeq);
        } catch (RemoteException ex) {
            throw ex.rethrowFromSystemServer();
        }
}

执行 handleBindApplication() 方法传入参数 AppBindData ,在最终创建 Application 前,data.info 被赋值 。接着调用到 LoadedApk.makeApplicationInner(boolean forceDefaultAppClass, Instrumentation instrumentation)

// LoadedApk.java

public Application makeApplicationInner(boolean forceDefaultAppClass,
        Instrumentation instrumentation) {
    return makeApplicationInner(forceDefaultAppClass, instrumentation,
            /* allowDuplicateInstances= */ false);
}

private Application makeApplicationInner(boolean forceDefaultAppClass,
        Instrumentation instrumentation, boolean allowDuplicateInstances) {
    if (mApplication != null) {
        return mApplication;
    }

	// ...
    Application app = null;

    final String myProcessName = Process.myProcessName();
    String appClass = mApplicationInfo.getCustomApplicationClassNameForProcess(
            myProcessName);
    if (forceDefaultAppClass || (appClass == null)) {
        appClass = "android.app.Application";
    }

    try {
        final java.lang.ClassLoader cl = getClassLoader();
		// ...
        // 创建方式与 ActivityThread 中 handleBindApplication 创建方式一致。
        ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this); 
 		// ...
        // 创建 Application
        app = mActivityThread.mInstrumentation.newApplication(cl, appClass, appContext);
        appContext.setOuterContext(app);
    } catch (Exception e) {
		// ...
    }
    mActivityThread.mAllApplications.add(app);
    mApplication = app;
	// ...
    if (instrumentation != null) {
        try {
            instrumentation.callApplicationOnCreate(app); // 调用了 Application 的声明周期方法 onCreate
        } catch (Exception e) {
           // ...
        }
    }
    return app;
}

最终调用的 Application 对象是在 Instrumentation 中创建。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
好的,我来给您编写这个程序。 首先,我们需要导入必要的模块:`tkinter`、`datetime`、`time`和`threading`。其中,`tkinter`用于构建GUI界面,`datetime`用于处理日期和时间,`time`用于等待时间,`threading`用于多线程。 ```python import tkinter as tk from datetime import datetime, timedelta import time import threading ``` 接下来,我们需要定义一个`Schedule`类,用于管理日程。在这个类中,我们需要定义一些属性和方法,如下: ```python class Schedule: def __init__(self, title, start_time, duration, interval, advance, repeat, repeat_type): self.title = title self.start_time = start_time self.duration = duration self.interval = interval self.advance = advance self.repeat = repeat self.repeat_type = repeat_type self.completed = False self.paused = False self.remind_thread = None def start(self): self.completed = False self.paused = False self.remind_thread = threading.Thread(target=self.remind) self.remind_thread.start() def pause(self): self.paused = True def resume(self): self.paused = False def stop(self): self.completed = True def remind(self): while not self.completed: if not self.paused: now = datetime.now() start_time = datetime.strptime(self.start_time, '%Y-%m-%d %H:%M:%S') delta = start_time - now + timedelta(minutes=self.advance) if delta.total_seconds() <= 0: self.show_reminder() if self.repeat: self.repeat_reminder() else: self.completed = True else: time.sleep(delta.total_seconds()) def show_reminder(self): duration = timedelta(minutes=self.duration) end_time = datetime.strptime(self.start_time, '%Y-%m-%d %H:%M:%S') + duration message = f"{self.title}\nStart time: {self.start_time}\nEnd time: {end_time.strftime('%Y-%m-%d %H:%M:%S')}" root = tk.Tk() root.title("Reminder") label = tk.Label(root, text=message, font=('Arial', 18)) label.pack() root.mainloop() def repeat_reminder(self): if self.repeat_type == 'daily': start_time = datetime.strptime(self.start_time, '%Y-%m-%d %H:%M:%S') + timedelta(days=1) self.start_time = start_time.strftime('%Y-%m-%d %H:%M:%S') elif self.repeat_type == 'weekly': start_time = datetime.strptime(self.start_time, '%Y-%m-%d %H:%M:%S') + timedelta(weeks=1) self.start_time = start_time.strftime('%Y-%m-%d %H:%M:%S') elif self.repeat_type == 'monthly': month = datetime.strptime(self.start_time, '%Y-%m-%d %H:%M:%S').month + 1 year = datetime.strptime(self.start_time, '%Y-%m-%d %H:%M:%S').year if month > 12: month = 1 year += 1 start_time = datetime(year, month, datetime.strptime(self.start_time, '%Y-%m-%d %H:%M:%S').day, datetime.strptime(self.start_time, '%Y-%m-%d %H:%M:%S').hour, datetime.strptime(self.start_time, '%Y-%m-%d %H:%M:%S').minute) self.start_time = start_time.strftime('%Y-%m-%d %H:%M:%S') elif self.repeat_type == 'yearly': year = datetime.strptime(self.start_time, '%Y-%m-%d %H:%M:%S').year + 1 month = datetime.strptime(self.start_time, '%Y-%m-%d %H:%M:%S').month day = datetime.strptime(self.start_time, '%Y-%m-%d %H:%M:%S').day hour = datetime.strptime(self.start_time, '%Y-%m-%d %H:%M:%S').hour minute = datetime.strptime(self.start_time, '%Y-%m-%d %H:%M:%S').minute start_time = datetime(year, month, day, hour, minute) self.start_time = start_time.strftime('%Y-%m-%d %H:%M:%S') ``` 在这个类中,我们定义了一个初始化方法`__init__`,用于初始化日程的属性。`start`方法用于启动日程,`pause`方法用于暂停日程,`resume`方法用于恢复日程,`stop`方法用于停止日程。`remind`方法是一个循环,用于等待日程的开始时间,并在开始时间前`advance`分钟提醒用户。如果设置了重复提醒,则在提醒后继续等待下一次提醒时间。`show_reminder`方法用于显示提醒窗口,`repeat_reminder`方法用于计算下一次重复提醒的时间。 接下来,我们需要定义一个`ScheduleManager`类,用于管理所有的日程。在这个类中,我们需要定义一些属性和方法,如下: ```python class ScheduleManager: def __init__(self): self.schedules = [] self.timer_thread = None def add_schedule(self, schedule): self.schedules.append(schedule) def start(self): self.timer_thread = threading.Thread(target=self.timer) self.timer_thread.start() def stop(self): for schedule in self.schedules: schedule.stop() self.timer_thread.join() def timer(self): while True: now = datetime.now() for schedule in self.schedules: start_time = datetime.strptime(schedule.start_time, '%Y-%m-%d %H:%M:%S') delta = start_time - now if delta.total_seconds() <= 0 and not schedule.completed: schedule.start() time.sleep(1) ``` 在这个类中,我们定义了一个初始化方法`__init__`,用于初始化管理器的属性。`add_schedule`方法用于添加日程到管理器中。`start`方法用于启动管理器,`stop`方法用于停止管理器。`timer`方法是一个循环,用于检查所有的日程是否已经到达开始时间,并启动日程。 最后,我们需要定义一个GUI界面,用于让用户输入日程的信息并添加到管理器中。在这个界面中,我们需要定义一些控件,如下: ```python class Application: def __init__(self, master): self.master = master self.master.title("Schedule Reminder") self.master.geometry("400x400") self.title_label = tk.Label(self.master, text="Title:", font=('Arial', 18)) self.title_label.pack() self.title_entry = tk.Entry(self.master, font=('Arial', 18)) self.title_entry.pack() self.start_time_label = tk.Label(self.master, text="Start Time (YYYY-MM-DD HH:MM:SS):", font=('Arial', 18)) self.start_time_label.pack() self.start_time_entry = tk.Entry(self.master, font=('Arial', 18)) self.start_time_entry.pack() self.duration_label = tk.Label(self.master, text="Duration (minutes):", font=('Arial', 18)) self.duration_label.pack() self.duration_entry = tk.Entry(self.master, font=('Arial', 18)) self.duration_entry.pack() self.interval_label = tk.Label(self.master, text="Interval (minutes):", font=('Arial', 18)) self.interval_label.pack() self.interval_entry = tk.Entry(self.master, font=('Arial', 18)) self.interval_entry.pack() self.advance_label = tk.Label(self.master, text="Advance (minutes):", font=('Arial', 18)) self.advance_label.pack() self.advance_entry = tk.Entry(self.master, font=('Arial', 18)) self.advance_entry.pack() self.repeat_label = tk.Label(self.master, text="Repeat:", font=('Arial', 18)) self.repeat_label.pack() self.repeat_var = tk.BooleanVar() self.repeat_checkbox = tk.Checkbutton(self.master, text="Repeat", variable=self.repeat_var, font=('Arial', 18)) self.repeat_checkbox.pack() self.repeat_type_label = tk.Label(self.master, text="Repeat Type:", font=('Arial', 18)) self.repeat_type_label.pack() self.repeat_type_var = tk.StringVar() self.repeat_type_var.set("daily") self.repeat_type_optionmenu = tk.OptionMenu(self.master, self.repeat_type_var, "daily", "weekly", "monthly", "yearly") self.repeat_type_optionmenu.config(font=('Arial', 18)) self.repeat_type_optionmenu.pack() self.add_button = tk.Button(self.master, text="Add", font=('Arial', 18), command=self.add_schedule) self.add_button.pack() self.schedule_manager = ScheduleManager() def add_schedule(self): title = self.title_entry.get() start_time = self.start_time_entry.get() duration = int(self.duration_entry.get()) interval = int(self.interval_entry.get()) advance = int(self.advance_entry.get()) repeat = self.repeat_var.get() repeat_type = self.repeat_type_var.get() schedule = Schedule(title, start_time, duration, interval, advance, repeat, repeat_type) self.schedule_manager.add_schedule(schedule) def start(self): self.schedule_manager.start() ``` 在这个界面中,我们定义了一个初始化方法`__init__`,用于初始化界面的控件。`add_schedule`方法用于获取用户输入的日程信息并添加到管理器中。`start`方法用于启动管理器。 最后,我们需要创建一个`Application`对象并启动界面: ```python root = tk.Tk() app = Application(root) app.start() root.mainloop() ``` 这样,我们就完成了这个程序的编写。完整的代码如下:
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

VoidHope

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值