android系统serviceManger源码解析

news/2024/5/19 16:40:31

一,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.mrgr.cn/p/26700711

相关文章

js 金额计算时数值溢出

js 计算乘算时数字溢出场景项目上为了计算税率相乘,金额有小数点乘以税率后会导致部分数字溢出,为了解决数字溢出。使用 bignumber.js 库:安装 npm run install bignumber.js使用:效果图// 引入BigNumberconst BigNumber = require("bignumber.js");created() {c…

Go-Zero技能提升:深度探究goctl的妙用,轻松应对微服务开发挑战!(三)

深入解析Go-Zero的goctl工具,从0到1学会使用,快速生成api服务、rpc服务脚手架,提高开发效率!前言 有位同学在群里说:“Go-Zero官方文档太简洁了,对小白有点不友好。好奇你们是怎么学习的?项目是怎么封装的?有什么提高开发效率的技巧吗?”。 来来来,这期内容给你安排上…

rocketMQ一

参考: 图灵课堂:https://vip.tulingxueyuan.cnMQ简介 MQ:MessageQueue,消息队列。是在互联网中使用非常广泛的一系列服务中间件。 这个词可以分两个部分来看, 一是Message:消息。消息是在不同进程之间传递的数据。这些进程可以部署在同一台机器上,也可以分布在不同机器上…

深入剖析:如何使用Pulsar和Arthas高效排查消息队列延迟问题

背景 前两天收到业务反馈有一个 topic 的分区消息堆积了:根据之前的经验来看,要么是业务消费逻辑出现问题导致消费过慢,当然也有小概率是消息队列的 Bug(我们使用的是 pulsar)。 排查通过排查,发现确实是在一点多的时候消息堆积了(后面是修复之后堆积开始下降)。 于是我…

五一反向旅游,景区“AI+视频监控”将持续助力旅游业发展

一、建设背景 每年五一劳动节出去旅游都是人挤人状态&#xff0c;这导致景区的体验感极差。今年“五一反向旅游”的话题冲上了热搜&#xff0c;好多人选择了五一之后再出去旅游&#xff0c;避开拥挤的人群&#xff0c;这个时候景区的监管力度和感知能力就更要跟上去&#xff0…

openGauss 冲突处理

冲突处理 逻辑复制的行为类似于正常的DML操作,即便数据在订阅者节点本地被修改,逻辑复制也会根据收到的更改来更新数据。如果流入的数据违背了任何约束,复制将停止。这种情况被称为一个冲突。在复制UPDATE或DELETE操作时,缺失的数据将不会产生冲突并且这类操作将被简单地跳…

基于大语言模型多智体的综述:进步和挑战!

源自&#xff1a; 人工智能前沿讲习 “人工智能技术与咨询” 发布 声明:公众号转载的文章及图片出于非商业性的教育和科研目的供大家参考和探讨&#xff0c;并不意味着支持其观点或证实其内容的真实性。版权归原作者所有&#xff0c;如转载稿涉及版权等问题&#xff0c;请立即…

数塔问题(蛮力算法和动态规划)

题目&#xff1a;如下图是一个数塔&#xff0c;从顶部出发在每一个节点可以选择向左或者向右走&#xff0c;一直走到底层&#xff0c;要求找出一条路径&#xff0c;使得路径上的数字之和最大&#xff0c;及路径情况。(使用蛮力算法和动态规划算法分别实现&#xff09; #include…

Linux下使用RAID

目录 1. 创建RAID准备 2. 创建RAID 0 2.1. 创建磁盘阵列 &#xff08;1&#xff09;创建磁盘阵列 &#xff08;2&#xff09;查看磁盘阵列信息 &#xff08;3&#xff09;挂载文件系统 &#xff08;4&#xff09;保存RAID信息 &#xff08;5&#xff09;开机自动挂载RA…

LeetCode-DFS-树类-简单难度

关于二叉树的相关深度优先遍历类题目&#xff0c;重点在于掌握最基本的前中后序遍历&#xff0c;大多数题目都在围绕这套逻辑&#xff0c;找到处理节点的时机&#xff0c;以及停止遍历的条件&#xff0c;即可顺利完成。 二叉树前中后序遍历模板 所谓前中后序&#xff0c;指的…

Python中的分布式爬虫系统Scrapy与分布式任务队列的结合

随着互联网的不断发展&#xff0c;网络爬虫在数据采集和信息挖掘中发挥着重要作用。然而&#xff0c;单机爬虫往往难以应对大规模数据抓取的需求&#xff0c;因此&#xff0c;构建分布式爬虫系统成为了一种必然选择。本文将介绍如何利用 Python 中的 Scrapy 框架和分布式任务队…

No space left on device

报错提示 [ERROR] Upload Local File hwzt-third-party-out.jar Failed [ERROR] java.lang.RuntimeException: cp: error writing : No space left on device [ERROR] com.alibabacloud.commons.ssh.sshj.SshjConnection.executeCustomCharset(SshjConnection.java:172) …

Anaconda删除虚拟环境目录pkgs和envs|conda瘦身

这个文件夹里面是专门放不同环境中的包的&#xff0c;只是没有区分环境&#xff0c;都混在一起了&#xff0c; 一般在想要删除一个虚拟环境&#xff0c;除了在命令行中输入conda remove -n your_env_name(虚拟环境名称) --all 然后在envs中删除虚拟环境的文件夹&#xff0c; 还…

如何完美解决Outlook大文件传送问题,提升办公协作效率?

在日常工作中,邮件是一种常用的通信方式,经常用来发送各类文件,比如报告和文档、合同和协议、财务报表、营销资料、设计文件等。但有时文件会比较大,因此Outlook大文件传送时,会遇到附件大小受限的情况。常用的解决发送大文件的问题有以下几种: 1.压缩文件:如果文件大小…

Docker私有仓库与Harbor部署使用

目录 一、本地私有仓库 1. 下载registry镜像 2. 在daemon.json文件中添加私有镜像仓库地址 ​编辑 3. 运行registry容器 4. Docker容器的重启策略如下 5. 为镜像打标签 6. 上传到私有仓库 7. 列出私有仓库的所有镜像 8. 列出私有仓库的centos镜像有哪些tag 9. 先删…

记一次java进程频繁挂掉问题排查修复

前言 最近业务部门有个java服务进程会突然无缘无故的挂掉,然后这个服务会产生一堆类似hs_err_pid19287.log这样的日志。业务部门负责人就把hs_err_pidxxx的日志发给我,让我帮忙看下问题。本文就来回顾一下,我是如何帮业务部门进行问题排查 排查历程 首先hs_err_pidxxx的日志…

BigDecimal精度理解

BigDecimal的类声明以及几个属性:接下来我们可以debug来看下其运行原理BigDecimal bigDecimal1 = BigDecimal.valueOf(2.88);BigDecimal bigDecimal2 = BigDecimal.valueOf(3.5);BigDecimal resDecimal = bigDecimal1.add(bigDecimal2);System.out.println(resDecimal); 可以看…

linux使用blkid未显示所有设备的UUID

如题: 使用lsblk命令可以看到,服务器存在设备vdb但使用blkid命令,系统未返回所有硬盘的UUID同时,使用lsblk -f命令,可以看到系统返回的设备挂载情况,也没有返回vdb的信息解决方案: 查询资料,看到有一个解决方法 使用sudo blkid进行查询,发现可以查询到/dev/vdb设备的U…

HFSS学习-day1-T形波导的内场分析和优化设计

入门实例--T形波导的内场分析和优化设计 HFSS--此实例详细步骤1.创建项目2.设置求解类型3.设置与建模相关的一些信息设置默认的建模长度单位 4.创建T形模型的三个臂基本参数端口激励进行复制 5.创建被挖去的部分设置正确的边界条件和端口激励方式添加求解设置添加扫频项检查一下…

opencv基础篇 ——(十六)图形绘制与填充

OpenCV 提供了丰富的图形绘制和填充功能&#xff0c;主要通过 cv::rectangle, cv::circle, cv::line, cv::polylines, cv::fillPoly 和 cv::ellipse 等函数实现。以下是一些基本的图形绘制和填充操作的说明&#xff1a; 矩形: 函数: cv::rectangle语法: cv::rectangle(img, rec…