ActivityManagerService

news2024/9/22 11:24:05

1 AMS 家族

ActivityManagerService(AMS)主要负责系统中四大组件的启动、切换、调度以及应用程序的管理和调度工作,其职责与操作系统中的进程管理和调度模块类似。ActivityManagerService 进行初始化的时机很明确,就是在 system_server 进程开启的时候,就会初始化 ActivityManagerService。(启动 APP 的时候,是需要 AMS 通知 Zygote 进程,所有的 Activity 的生命周期都需要 AMS 来控制)

ActivityThread 在 Android 中代表主线程,在 APP 进程创建完成之后,就会加载 ActivityThread.main 函数,然后执行 Looper.loop() 循环,使当前线程进入消息循环。ApplicationThread 是 ActivityThread 的内部类,继承了 IApplicationThread.Stub。如果需要在目标进程中启动 Activity,就要通过 ApplicationThread 与 AMS 所在的进程(system_server 进程)进行通信。

AMS与引用程序进行通信

1.1 Android 7.0 的 AMS 家族

ActivityManager 是一个和 AMS 相关联的类,主要是对运行中的 Activity 进行管理,但是,这些管理工作并不是直接由 ActivityManager 管理的,而是交由 AMS 来处理。

ActivityManager 中的方法会通过 ActivityManagerNative(AMN).getDefault() 方法来得到 ActivityManagerProxy(AMP),通过 AMP 就可以和 AMN 进行通信。AMN 是一个抽象类,它将功能交给它的子类 AMS 来处理,因此,AMP 就是 AMS 的代理类。

以下是相关类:

public interface IInterface{
    public IBinder asBinder();
}

public interface IBinder { 
    public boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException;
}

public class Binder implements IBinder { }

public interface IActivityManager extends IInterface { }

public abstract class ActivityManagerNative extends Binder implements IActivityManager { 
    class ActivityManagerProxy implements IActivityManager { }
}

public final class ActivityManagerService extends ActivityManagerNative
    implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback { }

AMS 作为系统服务,很多 API 是不会暴露给 ActivityManager 的,因此 ActivityManager 并不算是 AMS 家族中的一份子。以下会以 Android 7.0 的 Activity 启动过程来举例,在 Activity 的启动过程中会调用 Instrumentation.execStartActivity 方法:

// /frameworks/base/core/java/android/app/Instrumentation.java
public ActivityResult execStartActivity(
    ...
    try {
        intent.migrateExtraStreamToClipData();
        intent.prepareToLeaveProcess(who);
        int result = ActivityManagerNative.getDefault()
            .startActivity(whoThread, who.getBasePackageName(), intent,
                           intent.resolveTypeIfNeeded(who.getContentResolver()),
                           token, target, requestCode, 0, null, options);
        checkStartActivityResult(result, intent);
    } catch (RemoteException e) {
        throw new RuntimeException("Failure from system", e);
    }
    return null;
}

AMS 和 ActivityThread 之间,比如 Activity 的创建、暂停等交互工作实际上是由 Instumentation 具体操作的。每个 Activity 都持有一个 Instrumentation 对象的引用,整个进程中也只有一个 Instrumentation。mInstrumentation 的初始化在 ActivityThread.handleBindApplication 函数中,可以用来独立地控制某个组件的生命周期。Activity.startActivity 方法调用 mInstrumentation.execStartActivity 方法,最终,通过 AMS 告知 Zygote 进程 fork 子进程。

// /frameworks/base/core/java/android/app/ActivityThread.java
private void handleBindApplication(AppBindData data) {
    ...
    if (ii != null) {
        ...
        try {
            final ClassLoader cl = instrContext.getClassLoader();
            mInstrumentation = (Instrumentation)
                cl.loadClass(data.instrumentationName.getClassName()).newInstance();
        } catch (Exception e) {
            throw new RuntimeException(
                "Unable to instantiate instrumentation "
                + data.instrumentationName + ": " + e.toString(), e);
        }
        ...
    } else {
        mInstrumentation = new Instrumentation();
    }

}

Instrumentation.execStartActivity 方法中会调用 ActivityManagerNative(AMN).getDefault() 方法来获取 AMS 的代理类 AMP,接着调用了 ActivityManagerProxy(AMP).startActivity 方法。 首先来看 ActivityMangerNative.getDefault() 方法:

/frameworks/base/core/java/android/app/ActivityManagerNative.java

static public IActivityManager getDefault() {
    return gDefault.get();
}

private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {
    protected IActivityManager create() {
        IBinder b = ServiceManager.getService("activity"); // 1
        if (false) {
            Log.v("ActivityManager", "default service binder = " + b);
        }
        IActivityManager am = asInterface(b); // 2
        if (false) {
            Log.v("ActivityManager", "default service = " + am);
        }
        return am;
    }
};

// frameworks/base/core/java/android/util/Singleton.java
public abstract class Singleton<T> {
    private T mInstance;

    protected abstract T create();

    public final T get() {
        synchronized (this) {
            if (mInstance == null) {
                mInstance = create();
            }
            return mInstance;
        }
    }
}

ActivityManagerNative.getDefault() 方法中调用了 gDefault.get() 方法,gDefault 是一个 Singleton 类。在注释1 处得到名为 “activity” 的 Service 引用,也就是 IBinder 类型的 AMS 的引用。接着在注释 2 处将它封装成 AMP 类型对象,并将它保存到 gDefault 中,此后调用 ActivityManagerNative.getDefault() 方法就会直接获取 AMS 的代理对象 AMP。 注释 2 处的 asInterface 方法如下所示:

/frameworks/base/core/java/android/app/ActivityManagerNative.java

static public IActivityManager asInterface(IBinder obj) {
    if (obj == null) {
        return null;
    }
    IActivityManager in =
        (IActivityManager)obj.queryLocalInterface(descriptor); // 1
    if (in != null) {
        return in;
    }

    return new ActivityManagerProxy(obj); // 2
}

注释 1 处的 descriptor 值为 android.app.IActivityManager,注释 1 处的代码主要用来查询本地进程是否有 IActivityManager 接口的实现,如果有则返回,如果没有,就在注释 2 处将 IBinder 类型的 AMS 引用封装成 AMP,AMP 的构造方法如下所示:

/frameworks/base/core/java/android/app/ActivityManagerNative.java

class ActivityManagerProxy implements IActivityManager {
    public ActivityManagerProxy(IBinder remote) {
        mRemote = remote;
    }
    ...
}

在 AMP 的构造方法中将 AMS 的引用赋值给变量 mRemote,这样在 AMP 中就可以使用 AMS 了。其中,IActivityManager 是一个接口,AMN 和 AMP 都实现了这个接口,用于实现代理模式和 Binder 通信。

再回到 Instrumentation.execStartActivity 方法中,查看 ActivityManagerProxy(AMP).startActivity 方法,AMP 是 AMN 的内部类,代码如下所示:

/frameworks/base/core/java/android/app/ActivityManagerNative.java

public int startActivity(IApplicationThread caller, String callingPackage, Intent intent, 
         String resolvedType, IBinder resultTo, String resultWho, int requestCode, 
         int startFlags, ProfilerInfo profilerInfo, Bundle options) throws RemoteException {
    ...
    data.writeInt(requestCode);
    data.writeInt(startFlags);
    ...
    mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0); // 1
    reply.readException();
    int result = reply.readInt();
    reply.recycle();
    data.recycle();
    return result;
}

首先将传入的参数写入到 Parcel 类型的 data 中。在注释 1 处,通过 IBinder 类型对象 mRemote(AMS 的引用)向服务端的 AMS 发送一个 START_ACTIVITY_TRANSACTION 类型的进程间通信请求,之后,服务端 AMS 就会从 Binder 线程池中读取客户端发来的数据,最终会调用 ActivityManagerNative.onTransact 方法,如下所示:

/frameworks/base/core/java/android/app/ActivityManagerNative.java

@Override
public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
    throws RemoteException {
    switch (code) {
        case START_ACTIVITY_TRANSACTION:
            {
                ...
                int result = startActivity(app, callingPackage, intent, resolvedType,
                       resultTo, resultWho, requestCode, startFlags, profilerInfo, options);
                reply.writeNoException();
                reply.writeInt(result);
                return true;
            }
            ...
    }

ActivityManagerNative.onTransact 方法中会调用 ActivityManagerService.startActivity 方法,如下所示:

/frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

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

startActivityAsUser 方法最后会返回 ActivityStarter 的 startActivityMayWait 方法。

以下是时序图:

请求AMS时序图

以下是 AMS 家族:

AMS家族族

AMP 是 AMN 的内部类,它们都实现了 IActivityManager 接口,这样它们就可以实现代理模式,具体来讲是远程代理:AMN 和 AMP 是运行在两个进程中的,AMP 是 Client 端,AMN 则是 Server 端,而 Server 端中具体的功能都是由 AMN 的子类 AMS 来实现的。因此,AMP 就是 AMS 在 Client 端的代理类。AMN 又实现了 Binder 类,这样 AMP 和 AMS 就可以通过 Binder 来进行进程间通信。ActivityManager 通过 AMN 的 getDefault() 方法得到 AMP,通过 AMP 就可以和 AMS 进行通信。 除了 ActivityManager,有些需要与 AMS 进行通信的类也需要通过 AMP,如图所示:

AMP和AMS进行通信

1.2 Android 8.0 的家族

Android 8.0 的 AMS 家族和 Android 7.0 有一些差别。以下是相关类:

interface IActivityManager { }

public class ActivityManagerService extends IActivityManager.Stub 
    implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback { }

还是以 Activity 的启动过程举例,在 Activity 的启动过程中会调用 Instrumentation.execStartActivity 方法:

frameworks/base/core/java/android/app/Instrumentation.java

public ActivityResult execStartActivity(Context who, IBinder contextThread, IBinder token,
                                        String target, Intent intent, int requestCode, 
                                        Bundle options) {
    ...
    try {
        intent.migrateExtraStreamToClipData();
        intent.prepareToLeaveProcess(who);
        int result = ActivityManager.getService()
            .startActivity(whoThread, who.getBasePackageName(), intent,
                           intent.resolveTypeIfNeeded(who.getContentResolver()),
                           token, target, requestCode, 0, null, options);
        checkStartActivityResult(result, intent);
    } catch (RemoteException e) {
        throw new RuntimeException("Failure from system", e);
    }
    return null;
}

这里调用的是 ActivityManager.getService() 方法,如下所示:

/frameworks/base/core/java/android/app/ActivityManager.java

public static IActivityManager getService() {
    return IActivityManagerSingleton.get();
}

private static final Singleton<IActivityManager> IActivityManagerSingleton =
    new Singleton<IActivityManager>() {
    @Override
    protected IActivityManager create() {
        final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE); // 1
        final IActivityManager am = IActivityManager.Stub.asInterface(b); // 2
        return am;
    }
}; 

ActivityManager.getService() 方法调用了 IAcitivitySingleton.get() 方法,IActivityManagerSingleton 是一个 Singleton 类。在注释 1 出得到名为 “activity” 的 Service 引用(Context.ACTIVITY_SERVICE 的值为 “activity”),也就是 IBinder 类型的 AMS 的引用。接着在注释 2 处将它转换成 IActivityManager 类型的对象,这段代码采用的是 AIDL,IActivityManager 类是由 AIDL 工具在编译时自动生成的,IActivityManager.aidl 的文件路径为 /frameworks/base/core/java/android/app/IActivityManager.aidl。要实现进程间通信,服务器端也就是 AMS 只需要继承 IActivityManager.Stub 类并实现相应的方法就可以了。

采用 AIDL 后就不需要使用 AMS 的代理类 AMP 了,因此,Android 8.0 去掉了 AMP,代替它的是 IAcitivityManager,它是 AMS 的本地代理。

以下是 Android 8.0 的时序图:

请求AMS时序图

对比之下,Android 8.0 的 AMS 家族要简单的多,ActivityManager.getService() 方法会得到 IActivityManager,AMS 只需要继承 IAcitivytManager.Stub 类,就可以和 ActivityManager 实现进程间通信了。

AMS家族

2 AMS 的启动过程

AMS 的启动是在 system_server 进程中启动的,这里从 SystemServer.main 方法讲起,代码如下所示:

// /frameworks/base/services/java/com/android/server/SystemServer.java
public static void main(String[] args) {
    new SystemServer().run();
}

SystemServer.main 方法只调用了 SystemServe().run() 方法,代码如下所示:

// /frameworks/base/services/java/com/android/server/SystemServer.java
private void run() {
    try {
        ...
        // 创建消息 Looper
        Looper.prepareMainLooper(); 
		// Initialize native services. 加载动态库 libandroid_servers.so
        System.loadLibrary("android_servers"); // 1 
        performPendingShutdown();
		// Initialize the system context. 创建系统的 Context
        createSystemContext(); 
        // Create the system service manager. 创建 SystemServiceManager
        mSystemServiceManager = new SystemServiceManager(mSystemContext); // 2
        mSystemServiceManager.setRuntimeRestarted(mRuntimeRestart);
        LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);
        // Prepare the thread pool for init tasks that can be parallelized
        SystemServerInitThreadPool.get();
    } finally {
        traceEnd();  // InitBeforeStartServices
    }

    // Start services.
    try {
        traceBeginAndSlog("StartServices");
        startBootstrapServices(); // 3 启动引导服务
        startCoreServices(); // 4 启动核心服务
        startOtherServices(); // 5 启动其他服务
        SystemServerInitThreadPool.shutdown();
    } catch (Throwable ex) {
        Slog.e("System", "******************************************");
        Slog.e("System", "************ Failure starting system services", ex);
        throw ex;
    } finally {
        traceEnd();
    }

    ...
    // Loop forever.
    Looper.loop();
    throw new RuntimeException("Main thread loop unexpectedly exited");
}

SystemServer.run() 方法中,注释 1 处加载了动态库 libandroid_servers.so,在注释 2 处创建了 SystemServiceManager,它会对系统的服务进行创建、启动和生命周期管理。在注释 3 处的 startBootstrapServices() 方法中用 SystemServiceManager 启动了 ActivityManagerService、PowerManagerService、PackageManagerService 等服务。在注释 4 处的 startCoreServices() 方法中则启动了 DropBoxManagerService、BatterService、UsageStatsService 和 WebViewUpdateService。在注释 5 处的 startOtherService() 方法中启动了 CameraService、AlarmManagerService、VrManagerService 等服务。这些服务的父类均为 SystemService。从注释 3、注释 4、注释 5 处的方法可以看出,官方把系统服务分成了 3 种类型,分别是引导服务、核心服务和其他服务,其中其他服务是一些非紧要和不需要立即启动的服务。 这里主要是看 AMS 是如何启动的,注释 3 处的 startBooststrapServices() 方法如下所示:

/frameworks/base/services/java/com/android/server/SystemServer.java

private void startBootstrapServices() {
    ...
    // Activity manager runs the show.
    traceBeginAndSlog("StartActivityManager");
    mActivityManagerService = mSystemServiceManager.startService(
        ActivityManagerService.Lifecycle.class).getService(); // 1
    mActivityManagerService.setSystemServiceManager(mSystemServiceManager);
    mActivityManagerService.setInstaller(installer);
    traceEnd();
	...
}

在注释 1 处调用了 SystemServiceManager.startService 方法,该方法的参数是 ActivityManagerService.Lifecycle.class :

/frameworks/base/services/core/java/com/android/server/SystemServiceManager.java

@SuppressWarnings("unchecked")
public <T extends SystemService> T startService(Class<T> serviceClass) {
    try {
        final String name = serviceClass.getName();
        Slog.i(TAG, "Starting " + name);
        Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "StartService " + name);

        // Create the service.
        if (!SystemService.class.isAssignableFrom(serviceClass)) {
            throw new RuntimeException("Failed to create " + name + ": service must extend " 
                                       + SystemService.class.getName());
        }
        final T service;
        try {
            Constructor<T> constructor = serviceClass.getConstructor(Context.class);
            service = constructor.newInstance(mContext);
        } catch (InstantiationException ex) {
            throw new RuntimeException("Failed to create service " + name
                                       + ": service could not be instantiated", ex);
        } catch (IllegalAccessException ex) {
            throw new RuntimeException("Failed to create service " + name 
                     + ": service must have a public constructor with a Context argument", ex);
        } catch (NoSuchMethodException ex) {
            throw new RuntimeException("Failed to create service " + name 
                    + ": service must have a public constructor with a Context argument", ex);
        } catch (InvocationTargetException ex) {
            throw new RuntimeException("Failed to create service " + name
                                       + ": service constructor threw an exception", ex);
        }

        startService(service);
        return service;
    } finally {
        Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
    }
}

public void startService(@NonNull final SystemService service) {
    mServices.add(service); // 1
    long time = System.currentTimeMillis();
    try {
        service.onStart(); // 2
    } catch (RuntimeException ex) {
        throw new RuntimeException("Failed to start service " + service.getClass().getName()
                                   + ": onStart threw an exception", ex);
    }
    warnIfTooLong(System.currentTimeMillis() - time, service, "onStart");
}

传入的 SystemService 类型的 service 对象的值为 ActivityManagerService.Lifecycle.class。在注释 1 处将 service 对象添加到 ArrayList 类型的 mServices 中来完成注册。在注释 2 处调用 service.onStart() 方法来启动 service 对象,这个 service 对象具体指的是什么呢?继续往下看,Lifecycle 是 AMS 的内部类:

public static final class Lifecycle extends SystemService {
    private final ActivityManagerService mService;

    public Lifecycle(Context context) {
        super(context);
        mService = new ActivityManagerService(context); // 1
    }

    @Override
    public void onStart() {
        mService.start(); // 2
    }

    public ActivityManagerService getService() { // 3
        return mService;
    }
}

上面的代码需要结合 SystemServiceManager.startService 方法来分析。注释 1 处,在 Lifecycle 的构造方法中创建了 AMS 实例。当调用 SystemService 类型的 service.onStart() 方法时,实际上是调用了注释 2 处 ActivityManagerService.start() 方法。注释 3 处的 Lifecycle.getService 方法返回 AMS 实例,这样,就知道 SystemServer.startBootstrapServices() 方法的注释 1 处 mSystemServiceManager.startService(ActivityManagerService.Lifecycle.class).getService() 实际得到的就是 AMS 实例。

以下是时序图:

AMS启动过程

3 AMS 与应用进程

在 Zygote 的 Java 框架层中,会创建一个 Server 端的 Socket,这个 Socket 用来等待 AMS 请求 Zygote 来创建新的应用程序进程。要启动一个应用程序,首先要保证这个应用程序所需要的应用程序进程已经存在。在启动应用程序时 AMS 会检查这个应用程序需要的应用程序进程是否存在,不存在就会请求 Zygote 进程创建需要的应用程序进程。

这里以 Service 的启动过程为例来分析 AMS 与应用程序进程的关系。Service 在启动过程中会调用 ActivityServices.bringUpServiceLocked 方法,如下所示:

// /frameworks/base/services/core/java/com/android/server/am/ActiveServices.java
private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
          boolean whileRestarting, boolean permissionsReviewRequired) 
    throws TransactionTooLargeException {
    ...
     // 获取 Service 想要在哪个进程运行   
    final String procName = r.processName; // 1
    String hostingType = "service";
    ProcessRecord app;

    if (!isolated) {
        app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false); // 2
        if (DEBUG_MU) Slog.v(TAG_MU, "bringUpServiceLocked: appInfo.uid=" + r.appInfo.uid
                             + " app=" + app);
        if (app != null && app.thread != null) { // 3
            try {
                app.addPackage(r.appInfo.packageName, r.appInfo.versionCode, mAm.mProcessStats);
                // 启动 Service
                realStartServiceLocked(r, app, execInFg); // 4
                return null;
            } catch (TransactionTooLargeException e) {
                throw e;
            } catch (RemoteException e) {
                Slog.w(TAG, "Exception when starting service " + r.shortName, e);
            }
        }
    } else {
        
        app = r.isolatedProc;
        if (WebViewZygote.isMultiprocessEnabled()
            && r.serviceInfo.packageName.equals(WebViewZygote.getPackageName())) {
            hostingType = "webview_service";
        }
    }

    // 如果用来运行 Service 的应用程序进程不存在
    if (app == null && !permissionsReviewRequired) { // 5
        // 创建应用程序进程
        if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,
                    hostingType, r.name, false, isolated, false)) == null) { // 6
            String msg = "Unable to launch app "
                + r.appInfo.packageName + "/"
                + r.appInfo.uid + " for service "
                + r.intent.getIntent() + ": process is bad";
            Slog.w(TAG, msg);
            bringDownServiceLocked(r);
            return msg;
        }
        if (isolated) {
            r.isolatedProc = app;
        }
    }

    ...

    return null;
}

在注释 1 出得到 ServiceRecord.processName 的值并赋值给 procName,其中,processName 用来描述 Service 想要在那个进程中运行,默认是当前进程,也可以在 AndroidManifest 文件中设置 android:process 属性来新开启一个进程运行 Service。在注释 2 处将 procName 和 Service 的 uid 传入到 AMS.getProcessRecordLocked 方法中,来查询是否存在一个与 Service 对应的 ProcessRecord 类型的对象 app,ProcessRecord 主要用来描述运行的应用程序进程的信息。在注释 5 处判断 Service 对应的 app == null 则说明用来运行 Service 的应用程序进程不存在,则调用注释 6 处的 AMS.startProcessLocked 方法来创建对应的应用程序进程。在注释 3 处判断如果用来运行 Service 的应用程序进程存在,则调用注释 4 处的 realStartServiceLocked 方法来启动 Service。

AMS 与应用程序进程的关系主要有以下两点:

  • 启动应用程序时 AMS 会检查这个应用程序需要的应用程序进程是否存在;
  • 如果需要的应用程序进程不存在,AMS 就会请求 Zygote 进程创建需要的应用程序进程;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/132742.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

计算机组成原理“上分秘籍”——数据的表示和运算

前言 上分地图 目录 前言 上分地图 猜你想问 Q1&#xff1a;为何要研究数据表示问题&#xff1f; Q2&#xff1a;什么叫数据表示&#xff1f;计算机中又有哪些方法&#xff1f; 正文 上分突破口1&#xff1a;进位计数法 例&#xff1a;二进制转为十进制 例&#xff…

路由综合实验

目录需求分析解决方法1&#xff0c;环回配置2&#xff0c;路由接口ip配置3&#xff0c;配置DHCP服务4&#xff0c;配置缺省5&#xff0c;静态路由配置6.浮动路由配置7&#xff0c;nat的配置8&#xff0c;远程服务及端口进行映射需求分析 一&#xff0c;原始需求如图&#xff1…

基于React Native开发的非法App破解记录

目标app YUhSMGNITTZMeTloWm1ZdWJIVnNkWE5wY2k1dFpTOD0 使用jadx反编译&#xff0c;找了一圈没有找到相应代码&#xff0c;看AndroidManifest.xml也不像有加壳的样子。。。 在lib目录下找到libreactnativejni.so文件&#xff0c;看似和react相关&#xff0c;莫非这app是大前端…

C++ Primer Plus 第六版(中文版)第五、六章(重置版)编程练习答案

//本博主所写的代码仅为阅读者提供参考&#xff1b; //若有不足之处请提出&#xff0c;博主会尽所能修改&#xff1b; //附上课后编程练习题目&#xff1b; //若是对您有用的话请点赞或分享提供给它人&#xff1b; //-----------------------------------------------------…

JavaScript奇淫技巧:反调试

JavaScript奇淫技巧&#xff1a;反调试 本文&#xff0c;将分享几种JS代码反调试技巧&#xff0c;目标是&#xff1a;实现防止他人调试、动态分析自己的代码。 检测调试&#xff0c;方法一&#xff1a;用console.log检测 代码&#xff1a; var c new RegExp ("1"…

Cesium 定位到图层(ImageryLayer)报错 DeveloperError: normalized result is not a number

Cesium 定位到图层&#xff08;ImageryLayer&#xff09;报错 DeveloperError: normalized result is not a number错误原因调试定位问题过程问题解决总结在使用 Cesium 封装代码的时候&#xff0c;遇到个奇怪的问题。 使用 viewer.flyTo(ImageryLayer) 报错&#xff1a;Devel…

【2022年度悲报】-回望2022,展望2023

文章目录一、前言-想对大家说的话二、有感而谈2022年-新年开端&#xff08;同销万古愁&#xff09;2022年-前中期&#xff08;再进再困&#xff0c;再熬再奋&#xff09;2022年-年后半段&#xff08;玉骨那愁瘴雾&#xff0c;冰姿自有仙风&#xff09;2022年-年末尾声&#xff…

简单总结:Flink和Kafka是如何做到精准一致性的

Flink CheckPoint机制 CheckPoint本质上就是检查点&#xff0c;类似于玩游戏的时候&#xff0c;需要偶尔存档&#xff0c;怕家里断电导致自己白玩。 Flink也是一样的&#xff0c;机器也是可能宕机&#xff0c;那么Flink如何保证自身不受宕机影响呢&#xff1f; 一般来说&am…

python小案例——采集财经数据

前言 大家早好、午好、晚好吖 ❤ ~ 另我给大家准备了一些资料&#xff0c;包括: 2022最新Python视频教程、Python电子书10个G &#xff08;涵盖基础、爬虫、数据分析、web开发、机器学习、人工智能、面试题&#xff09;、Python学习路线图等等 全部可在文末名片获取哦&…

MATLAB算法实战应用案例精讲-【人工智能】语义分割(补充篇)(附实战应用案例及代码)

前言 语义分割作为计算机视觉领域的关键任务,是实现完整场景理解的必经之路。为了让机器拥有视觉,要经过图像分类、物体检测再到图像分割的过程。其中,图像分割的技术难度最高。 越来越多的应用得益于图像分类分割技术,全场景理解在计算机视觉领域也至关重要。其中一些应…

强大的ANTLR4(3)--算术表达式

下面要构建一个简单的计算器&#xff0c;规则如下&#xff1a; 1&#xff09;可以由一系列语句构成&#xff0c;每条语句由换行符终止 2&#xff09;一条语句可以是表达式、赋值语句或空行 3&#xff09;可以有加减乘除、小括号以及变量出现 例如&#xff0c;文件名t.expr的内…

【Java】PriorityQueue梳理

【Java】PriorityQueue梳理 简介 PriorityQueue是优先队列的意思。优先队列的作用是能保证每次取出的元素都是队列中权值最小的。这里牵涉到了大小关系&#xff0c;元素大小的评判可以通过元素本身的自然顺序&#xff08;natural ordering&#xff09;&#xff0c;也可以通过…

linux的例行性工作

一&#xff0c;单一执行的例行性工作 定时任务&#xff0c;将来的某个时间点执行 使用单一理性工作的命令&#xff1a;at -> atd 命令 服务名 查看atd状态&#xff0c;看有没有这个服务&#xff0c;查看结果为有 我们使用 at 命令来生成所要运行的工作&#xff0c;并将…

Taro+nutui h5使用nut-signature 签名组件的采坑记录

近期在使用Taro&#xff08;“tarojs/taro”: “3.4.0-beta.0”&#xff09; Nutui &#xff08;3.1.16&#xff09;开发H5时,需要一个签名功能结果在小程序上运行正常的 nut-signature组件,在h5上出问题了 首先问题是 : Nutui的 签名组件&#xff08;nut-signature&#xff…

加解密与HTTPS(3)

您好&#xff0c;我是湘王&#xff0c;这是我的CSDN博客&#xff0c;欢迎您来&#xff0c;欢迎您再来&#xff5e; 除了对称加密算法和非对称加密算法&#xff0c;再就是最后的一种加密算法了&#xff1a;不可逆加密算法。 对称加密算法和非对称加密算法在处理明文的过程中需要…

线程池ThreadPoolExecutor的源码中是如何解决并发问题的?

ThreadPoolExecutor面临哪些线程安全问题 ThreadPoolExecutor俗称线程池&#xff0c;作为java.util.concurrent包对外提供基础实现&#xff0c;以内部线程池的形式对外提供管理任务执行&#xff0c;线程调度&#xff0c;线程池管理等等服务。 然而为高效并发而生ThreadPoolExe…

C++项目实战:职工管理系统

1.管理系统的要求 系统可以管理公司内部所有员工的信息 主要使用c实现一个基于多态的职工管理系统 公司中的职工分为三类&#xff1a;普通员工、经理、老板&#xff0c;显示信息时需要显示职工编号、职工姓名、职工岗位以及职责 普通员工职责&#xff1a;完成经理安排的各项任…

oh my 毕设-人体姿态估计综述

文章目录What is Human Pose Estimation?Classical vs. Deep Learning-based approachesClassical approaches to 2D Human Pose EstimationDeep Learning-based approaches to 2D Human Pose EstimationHuman Pose Estimation using Deep Neural NetworksOpenPoseAlphaPose (…

想要努力赚钱,培养四种基础能力

这四种基础能力分别是&#xff1a;认知力、学习力、执行力、复盘力。我们的认知和思维&#xff0c;很大程度上&#xff0c;都是由所处的环境和圈子决定的。在同一个环境和圈子里面呆久了&#xff0c;你的认知就会被固化了。穷人最根本的枷锁&#xff0c;不是缺乏资金&#xff0…

excel图表技巧:看看,这个饼图象不象罗盘?

说到制作柱形图、条形图、饼图&#xff0c;相信大家都没有问题&#xff0c;直接选中数据&#xff0c;再插入对应的图表就行了&#xff0c;可如果要制作一张双层饼图你还会吗&#xff1f;“啥&#xff1f;还有双层饼图&#xff1f;”嘿嘿&#xff0c;不知道了吧&#xff0c;双层…