android系统serviceManger源码解析

一,serviceManger时序图

本文涉及到的源码文件:

/frameworks/native/cmds/servicemanager/main.cpp
/frameworks/native/libs/binder/ProcessState.cpp
/frameworks/native/cmds/servicemanager/ServiceManager.cpp
/frameworks/native/libs/binder/IPCThreadState.cpp
/system/core/libutils/Looper.cpp
 ServiceManager是一个由C/C++编写的系统服务,源码位于/framework/native/cmds/servicemanager中,存在如下文件结构

java层SM

public final class ServiceManager {private static final String TAG = "ServiceManager";private static IServiceManager sServiceManager;private static HashMap<String, IBinder> sCache = new HashMap<String, IBinder>();private static IServiceManager getIServiceManager() {if (sServiceManager != null) {return sServiceManager;}// Find the service managersServiceManager = ServiceManagerNative.asInterface(Binder.allowBlocking(BinderInternal.getContextObject()));return sServiceManager;}/*** Returns a reference to a service with the given name.* * @param name the name of the service to get* @return a reference to the service, or <code>null</code> if the service doesn't exist*/public static IBinder getService(String name) {try {IBinder service = sCache.get(name);if (service != null) {return service;} else {return Binder.allowBlocking(getIServiceManager().getService(name));}} catch (RemoteException e) {Log.e(TAG, "error in getService", e);}return null;}/*** Returns a reference to a service with the given name, or throws* {@link NullPointerException} if none is found.** @hide*/public static IBinder getServiceOrThrow(String name) throws ServiceNotFoundException {final IBinder binder = getService(name);if (binder != null) {return binder;} else {throw new ServiceNotFoundException(name);}}/*** Place a new @a service called @a name into the service* manager.* * @param name the name of the new service* @param service the service object*/public static void addService(String name, IBinder service) {try {getIServiceManager().addService(name, service, false);} catch (RemoteException e) {Log.e(TAG, "error in addService", e);}}/*** Place a new @a service called @a name into the service* manager.* * @param name the name of the new service* @param service the service object* @param allowIsolated set to true to allow isolated sandboxed processes* to access this service*/public static void addService(String name, IBinder service, boolean allowIsolated) {try {getIServiceManager().addService(name, service, allowIsolated);} catch (RemoteException e) {Log.e(TAG, "error in addService", e);}}/*** Retrieve an existing service called @a name from the* service manager.  Non-blocking.*/public static IBinder checkService(String name) {try {IBinder service = sCache.get(name);if (service != null) {return service;} else {return Binder.allowBlocking(getIServiceManager().checkService(name));}} catch (RemoteException e) {Log.e(TAG, "error in checkService", e);return null;}}/*** Return a list of all currently running services.* @return an array of all currently running services, or <code>null</code> in* case of an exception*/public static String[] listServices() {try {return getIServiceManager().listServices();} catch (RemoteException e) {Log.e(TAG, "error in listServices", e);return null;}}/*** This is only intended to be called when the process is first being brought* up and bound by the activity manager. There is only one thread in the process* at that time, so no locking is done.* * @param cache the cache of service references* @hide*/public static void initServiceCache(Map<String, IBinder> cache) {if (sCache.size() != 0) {throw new IllegalStateException("setServiceCache may only be called once");}sCache.putAll(cache);}/*** Exception thrown when no service published for given name. This might be* thrown early during boot before certain services have published* themselves.** @hide*/public static class ServiceNotFoundException extends Exception {public ServiceNotFoundException(String name) {super("No service published for: " + name);}}
}

native层的SM

/** Copyright (C) 2005 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.*/#define LOG_TAG "ServiceManager"#include <binder/IServiceManager.h>#include <utils/Log.h>
#include <binder/IPCThreadState.h>
#include <binder/Parcel.h>
#include <utils/String8.h>
#include <utils/SystemClock.h>
#include <utils/CallStack.h>#include <private/binder/Static.h>#include <unistd.h>namespace android {sp<IServiceManager> defaultServiceManager()
{if (gDefaultServiceManager != NULL) return gDefaultServiceManager;{AutoMutex _l(gDefaultServiceManagerLock);while (gDefaultServiceManager == NULL) {gDefaultServiceManager = interface_cast<IServiceManager>(ProcessState::self()->getContextObject(NULL));if (gDefaultServiceManager == NULL)sleep(1);}}return gDefaultServiceManager;
}bool checkCallingPermission(const String16& permission)
{return checkCallingPermission(permission, NULL, NULL);
}static String16 _permission("permission");bool checkCallingPermission(const String16& permission, int32_t* outPid, int32_t* outUid)
{IPCThreadState* ipcState = IPCThreadState::self();pid_t pid = ipcState->getCallingPid();uid_t uid = ipcState->getCallingUid();if (outPid) *outPid = pid;if (outUid) *outUid = uid;return checkPermission(permission, pid, uid);
}bool checkPermission(const String16& permission, pid_t pid, uid_t uid)
{sp<IPermissionController> pc;gDefaultServiceManagerLock.lock();pc = gPermissionController;gDefaultServiceManagerLock.unlock();int64_t startTime = 0;while (true) {if (pc != NULL) {bool res = pc->checkPermission(permission, pid, uid);if (res) {if (startTime != 0) {ALOGI("Check passed after %d seconds for %s from uid=%d pid=%d",(int)((uptimeMillis()-startTime)/1000),String8(permission).string(), uid, pid);}return res;}// Is this a permission failure, or did the controller go away?if (IInterface::asBinder(pc)->isBinderAlive()) {ALOGW("Permission failure: %s from uid=%d pid=%d",String8(permission).string(), uid, pid);return false;}// Object is dead!gDefaultServiceManagerLock.lock();if (gPermissionController == pc) {gPermissionController = NULL;}gDefaultServiceManagerLock.unlock();}// Need to retrieve the permission controller.sp<IBinder> binder = defaultServiceManager()->checkService(_permission);if (binder == NULL) {// Wait for the permission controller to come back...if (startTime == 0) {startTime = uptimeMillis();ALOGI("Waiting to check permission %s from uid=%d pid=%d",String8(permission).string(), uid, pid);}sleep(1);} else {pc = interface_cast<IPermissionController>(binder);// Install the new permission controller, and try again.gDefaultServiceManagerLock.lock();gPermissionController = pc;gDefaultServiceManagerLock.unlock();}}
}// ----------------------------------------------------------------------class BpServiceManager : public BpInterface<IServiceManager>
{
public:explicit BpServiceManager(const sp<IBinder>& impl): BpInterface<IServiceManager>(impl){}virtual sp<IBinder> getService(const String16& name) const{unsigned n;for (n = 0; n < 5; n++){if (n > 0) {if (!strcmp(ProcessState::self()->getDriverName().c_str(), "/dev/vndbinder")) {ALOGI("Waiting for vendor service %s...", String8(name).string());CallStack stack(LOG_TAG);} else {ALOGI("Waiting for service %s...", String8(name).string());}sleep(1);}sp<IBinder> svc = checkService(name);if (svc != NULL) return svc;}return NULL;}virtual sp<IBinder> checkService( const String16& name) const{Parcel data, reply;data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());data.writeString16(name);remote()->transact(CHECK_SERVICE_TRANSACTION, data, &reply);return reply.readStrongBinder();}virtual status_t addService(const String16& name, const sp<IBinder>& service,bool allowIsolated){Parcel data, reply;data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());data.writeString16(name);data.writeStrongBinder(service);data.writeInt32(allowIsolated ? 1 : 0);status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);return err == NO_ERROR ? reply.readExceptionCode() : err;}virtual Vector<String16> listServices(){Vector<String16> res;int n = 0;for (;;) {Parcel data, reply;data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());data.writeInt32(n++);status_t err = remote()->transact(LIST_SERVICES_TRANSACTION, data, &reply);if (err != NO_ERROR)break;res.add(reply.readString16());}return res;}
};IMPLEMENT_META_INTERFACE(ServiceManager, "android.os.IServiceManager");}; // namespace android

真正的SM服务

/* Copyright 2008 The Android Open Source Project*/#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>#include <cutils/android_filesystem_config.h>
#include <cutils/multiuser.h>#include <selinux/android.h>
#include <selinux/avc.h>#include "binder.h"#ifdef VENDORSERVICEMANAGER
#define LOG_TAG "VendorServiceManager"
#else
#define LOG_TAG "ServiceManager"
#endif
#include <log/log.h>struct audit_data {pid_t pid;uid_t uid;const char *name;
};const char *str8(const uint16_t *x, size_t x_len)
{static char buf[128];size_t max = 127;char *p = buf;if (x_len < max) {max = x_len;}if (x) {while ((max > 0) && (*x != '\0')) {*p++ = *x++;max--;}}*p++ = 0;return buf;
}int str16eq(const uint16_t *a, const char *b)
{while (*a && *b)if (*a++ != *b++) return 0;if (*a || *b)return 0;return 1;
}static char *service_manager_context;
static struct selabel_handle* sehandle;static bool check_mac_perms(pid_t spid, uid_t uid, const char *tctx, const char *perm, const char *name)
{char *sctx = NULL;const char *class = "service_manager";bool allowed;struct audit_data ad;if (getpidcon(spid, &sctx) < 0) {ALOGE("SELinux: getpidcon(pid=%d) failed to retrieve pid context.\n", spid);return false;}ad.pid = spid;ad.uid = uid;ad.name = name;int result = selinux_check_access(sctx, tctx, class, perm, (void *) &ad);allowed = (result == 0);freecon(sctx);return allowed;
}static bool check_mac_perms_from_getcon(pid_t spid, uid_t uid, const char *perm)
{return check_mac_perms(spid, uid, service_manager_context, perm, NULL);
}static bool check_mac_perms_from_lookup(pid_t spid, uid_t uid, const char *perm, const char *name)
{bool allowed;char *tctx = NULL;if (!sehandle) {ALOGE("SELinux: Failed to find sehandle. Aborting service_manager.\n");abort();}if (selabel_lookup(sehandle, &tctx, name, 0) != 0) {ALOGE("SELinux: No match for %s in service_contexts.\n", name);return false;}allowed = check_mac_perms(spid, uid, tctx, perm, name);freecon(tctx);return allowed;
}static int svc_can_register(const uint16_t *name, size_t name_len, pid_t spid, uid_t uid)
{const char *perm = "add";if (multiuser_get_app_id(uid) >= AID_APP) {return 0; /* Don't allow apps to register services */}return check_mac_perms_from_lookup(spid, uid, perm, str8(name, name_len)) ? 1 : 0;
}static int svc_can_list(pid_t spid, uid_t uid)
{const char *perm = "list";return check_mac_perms_from_getcon(spid, uid, perm) ? 1 : 0;
}static int svc_can_find(const uint16_t *name, size_t name_len, pid_t spid, uid_t uid)
{const char *perm = "find";return check_mac_perms_from_lookup(spid, uid, perm, str8(name, name_len)) ? 1 : 0;
}struct svcinfo
{struct svcinfo *next;uint32_t handle;struct binder_death death;int allow_isolated;size_t len;uint16_t name[0];
};struct svcinfo *svclist = NULL;struct svcinfo *find_svc(const uint16_t *s16, size_t len)
{struct svcinfo *si;for (si = svclist; si; si = si->next) {if ((len == si->len) &&!memcmp(s16, si->name, len * sizeof(uint16_t))) {return si;}}return NULL;
}void svcinfo_death(struct binder_state *bs, void *ptr)
{struct svcinfo *si = (struct svcinfo* ) ptr;ALOGI("service '%s' died\n", str8(si->name, si->len));if (si->handle) {binder_release(bs, si->handle);si->handle = 0;}
}uint16_t svcmgr_id[] = {'a','n','d','r','o','i','d','.','o','s','.','I','S','e','r','v','i','c','e','M','a','n','a','g','e','r'
};uint32_t do_find_service(const uint16_t *s, size_t len, uid_t uid, pid_t spid)
{struct svcinfo *si = find_svc(s, len);if (!si || !si->handle) {return 0;}if (!si->allow_isolated) {// If this service doesn't allow access from isolated processes,// then check the uid to see if it is isolated.uid_t appid = uid % AID_USER;if (appid >= AID_ISOLATED_START && appid <= AID_ISOLATED_END) {return 0;}}if (!svc_can_find(s, len, spid, uid)) {return 0;}return si->handle;
}int do_add_service(struct binder_state *bs,const uint16_t *s, size_t len,uint32_t handle, uid_t uid, int allow_isolated,pid_t spid)
{struct svcinfo *si;//ALOGI("add_service('%s',%x,%s) uid=%d\n", str8(s, len), handle,//        allow_isolated ? "allow_isolated" : "!allow_isolated", uid);if (!handle || (len == 0) || (len > 127))return -1;if (!svc_can_register(s, len, spid, uid)) {ALOGE("add_service('%s',%x) uid=%d - PERMISSION DENIED\n",str8(s, len), handle, uid);return -1;}si = find_svc(s, len);if (si) {if (si->handle) {ALOGE("add_service('%s',%x) uid=%d - ALREADY REGISTERED, OVERRIDE\n",str8(s, len), handle, uid);svcinfo_death(bs, si);}si->handle = handle;} else {si = malloc(sizeof(*si) + (len + 1) * sizeof(uint16_t));if (!si) {ALOGE("add_service('%s',%x) uid=%d - OUT OF MEMORY\n",str8(s, len), handle, uid);return -1;}si->handle = handle;si->len = len;memcpy(si->name, s, (len + 1) * sizeof(uint16_t));si->name[len] = '\0';si->death.func = (void*) svcinfo_death;si->death.ptr = si;si->allow_isolated = allow_isolated;si->next = svclist;svclist = si;}binder_acquire(bs, handle);binder_link_to_death(bs, handle, &si->death);return 0;
}int svcmgr_handler(struct binder_state *bs,struct binder_transaction_data *txn,struct binder_io *msg,struct binder_io *reply)
{struct svcinfo *si;uint16_t *s;size_t len;uint32_t handle;uint32_t strict_policy;int allow_isolated;//ALOGI("target=%p code=%d pid=%d uid=%d\n",//      (void*) txn->target.ptr, txn->code, txn->sender_pid, txn->sender_euid);if (txn->target.ptr != BINDER_SERVICE_MANAGER)return -1;if (txn->code == PING_TRANSACTION)return 0;// Equivalent to Parcel::enforceInterface(), reading the RPC// header with the strict mode policy mask and the interface name.// Note that we ignore the strict_policy and don't propagate it// further (since we do no outbound RPCs anyway).strict_policy = bio_get_uint32(msg);s = bio_get_string16(msg, &len);if (s == NULL) {return -1;}if ((len != (sizeof(svcmgr_id) / 2)) ||memcmp(svcmgr_id, s, sizeof(svcmgr_id))) {fprintf(stderr,"invalid id %s\n", str8(s, len));return -1;}if (sehandle && selinux_status_updated() > 0) {
#ifdef VENDORSERVICEMANAGERstruct selabel_handle *tmp_sehandle = selinux_android_vendor_service_context_handle();
#elsestruct selabel_handle *tmp_sehandle = selinux_android_service_context_handle();
#endifif (tmp_sehandle) {selabel_close(sehandle);sehandle = tmp_sehandle;}}switch(txn->code) {case SVC_MGR_GET_SERVICE:case SVC_MGR_CHECK_SERVICE:s = bio_get_string16(msg, &len);if (s == NULL) {return -1;}handle = do_find_service(s, len, txn->sender_euid, txn->sender_pid);if (!handle)break;bio_put_ref(reply, handle);return 0;case SVC_MGR_ADD_SERVICE:s = bio_get_string16(msg, &len);if (s == NULL) {return -1;}handle = bio_get_ref(msg);allow_isolated = bio_get_uint32(msg) ? 1 : 0;if (do_add_service(bs, s, len, handle, txn->sender_euid,allow_isolated, txn->sender_pid))return -1;break;case SVC_MGR_LIST_SERVICES: {uint32_t n = bio_get_uint32(msg);if (!svc_can_list(txn->sender_pid, txn->sender_euid)) {ALOGE("list_service() uid=%d - PERMISSION DENIED\n",txn->sender_euid);return -1;}si = svclist;while ((n-- > 0) && si)si = si->next;if (si) {bio_put_string16(reply, si->name);return 0;}return -1;}default:ALOGE("unknown code %d\n", txn->code);return -1;}bio_put_uint32(reply, 0);return 0;
}static int audit_callback(void *data, __unused security_class_t cls, char *buf, size_t len)
{struct audit_data *ad = (struct audit_data *)data;if (!ad || !ad->name) {ALOGE("No service manager audit data");return 0;}snprintf(buf, len, "service=%s pid=%d uid=%d", ad->name, ad->pid, ad->uid);return 0;
}int main(int argc, char** argv)
{struct binder_state *bs;union selinux_callback cb;char *driver;if (argc > 1) {driver = argv[1];} else {driver = "/dev/binder";}bs = binder_open(driver, 128*1024);if (!bs) {
#ifdef VENDORSERVICEMANAGERALOGW("failed to open binder driver %s\n", driver);while (true) {sleep(UINT_MAX);}
#elseALOGE("failed to open binder driver %s\n", driver);
#endifreturn -1;}if (binder_become_context_manager(bs)) {ALOGE("cannot become context manager (%s)\n", strerror(errno));return -1;}cb.func_audit = audit_callback;selinux_set_callback(SELINUX_CB_AUDIT, cb);cb.func_log = selinux_log_callback;selinux_set_callback(SELINUX_CB_LOG, cb);#ifdef VENDORSERVICEMANAGERsehandle = selinux_android_vendor_service_context_handle();
#elsesehandle = selinux_android_service_context_handle();
#endifselinux_status_open(true);if (sehandle == NULL) {ALOGE("SELinux: Failed to acquire sehandle. Aborting.\n");abort();}if (getcon(&service_manager_context) != 0) {ALOGE("SELinux: Failed to acquire service_manager context. Aborting.\n");abort();}binder_loop(bs, svcmgr_handler);return 0;
}

二,serviceManger运行时时序图

从上述代码可以明确知道:ServiceManager程序一旦启动运行,则不会停止(系统不宕机的情况下),将会一直looper->pollAll(-1)。除此之外,还知道ServiceManager默认情况依托于/dev/binder这个设备节点,当然可以通过向ServiceManager传递参数指定设备节点。ServiceManager作为binder机制的核心组件之一,在实现进程间通信中占据着不可获取的地位。

从Android.bp可以知道,ServiceManager对应的程序名称是servicemanager。从Android.bp文件中,还存在一个名为vndservicemanager的程序,它们的源码都是一样的,只是rc文件存在出入,将传入/dev/vndbinder作为binder驱动。在Android启动启动过程中,vndservicemanager和vndservicemanager都会被init拉起,他俩的区别总结如下:

1、对于servicemanager:

servicemanager是 Android 系统中的核心服务管理器,用于管理系统级的服务。
servicemanager管理的服务包括系统级服务(如ActivityManager、PackageManager、WindowManager等)和由应用程序注册的系统服务。
servicemanager的访问权限较高,一般只有系统级应用或者具有系统权限的应用程序才能够使用servicemanager进行服务的注册和查询。
2、对于vndservicemanager:

vndservicemanager是 servicemanager的一个扩展,用于管理供应商特定的服务。
vndservicemanager管理的服务通常是供应商(vendor)特定的、定制化的服务,例如硬件厂商提供的驱动程序或服务。
vndservicemanager的访问权限一般较低,通常只有供应商特定的应用程序或系统组件才能够使用vndservicemanager进行服务的注册和查询。
二、ServiceManager的启动
第一小节简要介绍了ServiceManager,我们知道ServiceManager是一个具体程序,如果是个程序,那么该程序是如何启动的呢?又在什么时候触发运行的呢?

我们知道Android系统的第一个进程是init,这是由内核决定的。那么在init中将通过解析init.rc来启动系统的一些关键服务进程。其中ServiceManager就在这个时候启动运行
 

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

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

相关文章

C语言 循环控制流程的跳转语句

本文 我们来说 控制流程的跳转语句 C语言 提供三种 控制流程的跳转语句 1. break 语句 我们之前讲 switch 时 大家已经看到过这个 break 了 作用是跳出当前 switch 在循环中 它的作用也差不多 这里 我们举个生活中的例子 例如 我们在操场上跑步 计划跑十圈 但是 还没跑完 我…

负氧离子大气监测系统解析

TH-FZ5负氧离子大气监测系统是一个综合性的环境监测系统&#xff0c;主要用于实时监测和评估大气中负氧离子的浓度水平。负氧离子&#xff0c;也称为空气维生素&#xff0c;对人体健康和环境质量有重要影响。负氧离子大气监测系统通常包括以下几个主要组成部分&#xff1a; 负氧…

双重检验锁方式实现单例模式

单例模式&#xff08;Singleton Pattern&#xff09;&#xff1a;是指在内存中只会创建且仅创建一次对象的设计模式。在程序中多次使用同一个对象且作用相同时&#xff0c;为了防止频繁地创建对象使得内存飙升&#xff0c;单例模式可以让程序仅在内存中创建一个对象&#xff0c…

我是如何带团队从0到1做了AI中台

经历心得 我从18年初就开始带这小团队开始做项目&#xff0c;比如最初的数字广东的协同办公项目&#xff0c;以及粤信签小程序等&#xff0c;所以&#xff0c;在团队管理&#xff0c;人员安排&#xff0c;工作分工&#xff0c;项目拆解等方面都有一定的经验。 19年中旬&#…

WireShark对tcp通信数据的抓包

一、抓包准备工作 安装wireshark sudo apt update sudo apt install wireshark 运行 二、WireShark工具面板分析 上图中所显示的信息从上到下分布在 3 个面板中&#xff0c;每个面板包含的信息含义如下&#xff1a; Packet List 面板&#xff1a;显示 Wireshark 捕获到的所…

Qt QImageReader类介绍

1.简介 QImageReader 是用于读取图像文件的类。它提供了读取不同图像格式的功能&#xff0c;包括但不限于 PNG、JPEG、BMP 等。QImageReader 可以用于文件&#xff0c;也可以用于任何 QIODevice&#xff0c;如 QByteArray &#xff0c;这使得它非常灵活。 QImageReader 是一个…

【Docker】docker compose服务编排

docker compose 简介 Dockerfile模板文件可以定义一个单独的应用容器&#xff0c;如果需要定义多个容器就需要服务编排。 docker swarm&#xff08;管理跨节点&#xff09; Dockerfile可以让用户管理一个单独的应用容器&#xff1b;而Compose则允许用户在一个模板&#xff08…

商城数据库88张表结构完整示意图51~60(十三)

五十一&#xff1a; 五十二&#xff1a; 五十三&#xff1a; 五十四&#xff1a; 五十五&#xff1a; 五十六&#xff1a; 五十七&#xff1a; 五十八&#xff1a; 五十九&#xff1a; 六十&#xff1a;

GEE案例分析——2019年3月30日,四川省凉山州木里县雅砻江镇立尔村火灾面积分析(Sentinel-2和NBR)

简介 2019年3月30日18时许,四川省凉山州木里县雅砻江镇立尔村发生森林火灾,着火点在海拔3800米左右,地形复杂、坡陡谷深,交通、通讯不便。 1212据凉山州人民政府新闻办公室消息,火场在雅砻江边上,距木里县车程6到7个小时,火场平均海拔4000米,多个火点均位于悬崖上。森…

如何进行音频压缩大小?6个软件教你快速的压缩音频

如何进行音频压缩大小&#xff1f;6个软件教你快速的压缩音频 以下是六款常用的音频压缩软件&#xff0c;它们可以帮助您快速压缩音频文件大小&#xff1a; 迅捷视频剪辑软件&#xff1a; 这是一款非常实用的音频编辑软件&#xff0c;除了编辑音频外&#xff0c;它还提供了音…

文件加密软件排行榜前四名(2024年4大好用的加密软件推荐)

说到文件加密&#xff0c;想必大家都很熟悉&#xff0c;文件加密已经普遍应用&#xff0c;文件加密是一种重要的安全措施&#xff0c;可以确保数据的机密性、完整性和可用性&#xff0c;降低因数据泄露或丢失带来的风险 。 下面小编给大家分享几款常用的加密软件&#xff0c;…

权益商城系统源码 现支持多种支付方式

简介&#xff1a; 权益商城系统源码&#xff0c;支持多种支付方式&#xff0c;后台商品管理&#xff0c;订单管理&#xff0c;串货管理&#xff0c;分站管理&#xff0c;会员列表&#xff0c;分销日志&#xff0c;应用配置。 上传到服务器&#xff0c;修改数据库信息&#xff…

C++例题:大数运算---字符串相加(使用数字字符串来模拟竖式计算)

1.代码速览 class Solution2 { public:string addStrings(string num1, string num2){//end1和end1是下标int end1 num1.size() - 1;int end2 num2.size() - 1;string str;//下标(指针)从后向前走,走到头才可以结束,所以是end>0int next 0;while (end1 > 0 || end2 &…

Swift 周报 第五十期

文章目录 前言新闻和社区WWDC24&#xff1a;6 月 10 日至 14 日 (太平洋时间)苹果“内忧外患”&#xff0c;库克中国求援苹果被起诉&#xff01;市值一夜蒸发8000亿元 提案通过的提案正在审查的提案拒绝的提案 Swift论坛推荐博文话题讨论关于我们 前言 本期是 Swift 编辑组自主…

行业推荐:数据防泄漏软件首先解决方案

随着信息时代的快速发展&#xff0c;数据安全已成为企业经营的关键之一。然而&#xff0c;数据泄漏事件时有发生&#xff0c;不仅可能导致巨大的经济损失&#xff0c;更会损害企业的声誉和客户信任。 为了帮助企业有效地保护数据安全&#xff0c;Ping32 数据防泄漏系统应运而生…

SpringSecurity6配置requestMatchers().permitAll() 无效问题

版本 <spring-boot.version>3.0.2</spring-boot.version> <jjwt.version>0.12.5</jjwt.version>问题描述 题主在写 SpringSecurity6 JWT 做登录认证开发。一路跟着教程叭叭的敲。等到接口验证的时候&#xff0c;发现我的登录接口虽然在SecurityConf…

【Linux】掌握Linux系统编程中的权限与访问控制

&#x1f49e;&#x1f49e; 前言 hello hello~ &#xff0c;这里是大耳朵土土垚~&#x1f496;&#x1f496; &#xff0c;欢迎大家点赞&#x1f973;&#x1f973;关注&#x1f4a5;&#x1f4a5;收藏&#x1f339;&#x1f339;&#x1f339; &#x1f4a5;个人主页&#x…

电源小白入门学习7——USB充电、供电、电源路径管理

电源小白入门学习7——USB充电、供电、电源路径管理 USB充电系统需要考虑的因素开关充电和线性充电充电路径管理输入限流路径管理&#xff08;动态功率管理&#xff09;理想二极管帮助提高电池利用率输入过充抑制 上期我们介绍了锂离子电池的电池特性&#xff0c;及充电电路设计…

QT--1

类型界面 #include "mywidget.h"myWidget::myWidget(QWidget *parent): QWidget(parent) {//窗口相关设置this->resize(680,520);this->setFixedSize(680,520);this->setWindowTitle("Tim");this->setWindowFlag(Qt::FramelessWindowHint);th…

生成一个好故事!StoryDiffusion:一致自注意力和语义运动预测器必不可少(南开字节)

文章链接&#xff1a;https://arxiv.org/pdf/2405.01434 主页&#xff1a;https://storydiffusion.github.io/ 对于最近基于扩散的生成模型来说&#xff0c;在一系列生成的图像中保持一致的内容&#xff0c;尤其是那些包含主题和复杂细节的图像&#xff0c;是一个重大挑战。本…