Android系统在新进程中启动自定义服务过程(startService)的原理分析

发表于 5年以前  | 总阅读数:2536 次

在编写Android应用程序时,我们一般将一些计算型的逻辑放在一个独立的进程来处理,这样主进程仍然可以流畅地响应界面事件,提高用户体验。Android系统为我们提供了一个Service类,我们可以实现一个以Service为基类的服务子类,在里面实现自己的计算型逻辑,然后在主进程通过startService函数来启动这个服务。在本文中,将详细分析主进程是如何通过startService函数来在新进程中启动自定义服务的。

在主进程调用startService函数时,会通过Binder进程间通信机制来通知ActivitManagerService来创建新进程,并且启动指定的服务。在Android系统中,Binder进程间通信机制使用非常广泛,因此,希望读者在继续阅读下面的内容之前,对Android系统和Binder进程间通信机制有一定的了解,具体可以参考前面Android进程间通信(IPC)机制Binder简要介绍和学习计划一文。

关于startService的具体用法,可以参考前面Android系统匿名共享内存Ashmem(Anonymous Shared Memory)简要介绍和学习计划一文中用到的实例,它是Activity类的一个成员函数:

package shy.luo.ashmem;

    ......

    public class Client extends Activity implements OnClickListener {
        ......
        IMemoryService memoryService = null;
        ......

        @Override
        public void onCreate(Bundle savedInstanceState) {
            ......

            IMemoryService ms = getMemoryService();
            if(ms == null) {        
                startService(new Intent("shy.luo.ashmem.server"));
            } else {
                Log.i(LOG_TAG, "Memory Service has started.");
            }

            ......

            Log.i(LOG_TAG, "Client Activity Created.");
        }

        ......
    }

这里的"shy.luo.ashmem.server"是在程序配置文件AndroidManifest.xml配置的Service的名字,用来告诉Android系统它所要启动的服务的名字:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="shy.luo.ashmem"
        android:sharedUserId="android.uid.system"
        android:versionCode="1"
        android:versionName="1.0">
            <application android:icon="@drawable/icon" android:label="@string/app_name">
                ......
                <service 
                    android:enabled="true" 
                    android:name=".Server"
                    android:process=".Server" >
                        <intent-filter>
                            <action android:name="shy.luo.ashmem.server"/>
                            <category android:name="android.intent.category.DEFAULT"/>
                        </intent-filter>
                </service>
            </application>
    </manifest> 

这里,名字"shy.luo.ashmem.server"对应的服务类为shy.luo.ashmem.Server,下面语句:

startService(new Intent("shy.luo.ashmem.server"));

就表示要在一个新的进程中启动shy.luo.ashmem.Server这个服务类,它必须继承于Android平台提供的Service类:

package shy.luo.ashmem;

    ......

    public class Server extends Service {

        ......

        @Override
        public IBinder onBind(Intent intent) {
                return null;
        }

        @Override
        public void onCreate() {
            ......

        }

        ......
    }

下面,我们来看看Activity类中的startService成员函数是如何实现的。

先来看看Activity的类图:

从图中可以看出,Activity继承了ContextWrapper类,而在ContextWrapper类中,实现了startService函数。在ContextWrapper类中,有一个成员变量mBase,它是一个ContextImpl实例,而ContextImpl类和ContextWrapper类一样继承于Context类,ContextWrapper类的startService函数最终过调用ContextImpl类的startService函数来实现。这种类设计方法在设计模式里面,就称之为装饰模式(Decorator),或者包装模式(Wrapper)。

在ContextImpl类的startService类,最终又调用了ActivityManagerProxy类的startService来实现启动服务的操作,看到这里的Proxy关键字,回忆一下前面Android系统进程间通信Binder机制在应用程序框架层的Java接口源代码分析这篇文章,就会知道ActivityManagerProxy是一个Binder对象的远程接口了,而这个Binder对象就是我们前面所说的ActivityManagerService了。

这个ActivityManagerService类实现在frameworks/base/services/java/com/android/server/am/ActivityManagerService.java文件中,它是Binder进程间通信机制中的Server角色,它是随机启动的。随机启动的Server是在frameworks/base/services/java/com/android/server/SystemServer.java文件里面进行启动的,我们来看一下ActivityManagerService启动相关的代码:

class ServerThread extends Thread {

        ......

        @Override
        public void run() {

            ......

            // Critical services...
            try {

                ......

                context = ActivityManagerService.main(factoryTest);

                ......

                ActivityManagerService.setSystemProcess();

                ......

            } catch (RuntimeException e) {
                Slog.e("System", "Failure starting core service", e);
            }

            ......

        }

        ......

    }

首先是调用ActivityManagerService.main函数来创建一个ActivityManagerService实例,然后通过调用ActivityManagerService.setSystemProcess函数把这个Binder实例添加Binder进程间通信机制的守护进程ServiceManager中去:

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

        ......

        static ActivityManagerService mSelf;

        ......

        public static void setSystemProcess() {
            try {
                ActivityManagerService m = mSelf;

                ServiceManager.addService("activity", m);

                ......

            } catch (PackageManager.NameNotFoundException e) {
                ......
            }
        }

        ......

        public static final Context main(int factoryTest) {

            ......

            ActivityManagerService m = thr.mService;
            mSelf = m;

            ......

        }
    }

这样,ActivityManagerService就启动起来了。

回到ActivityManagerProxy类的startService函数中,它定义在frameworks/base/core/java/android/app/ActivityManagerNative.java文件中:

class ActivityManagerProxy implements IActivityManager
    {
        ......

        public ComponentName startService(IApplicationThread caller, Intent service,
            String resolvedType) throws RemoteException
        {
            Parcel data = Parcel.obtain();
            Parcel reply = Parcel.obtain();
            data.writeInterfaceToken(IActivityManager.descriptor);
            data.writeStrongBinder(caller != null ? caller.asBinder() : null);
            service.writeToParcel(data, 0);
            data.writeString(resolvedType);
            mRemote.transact(START_SERVICE_TRANSACTION, data, reply, 0);
            reply.readException();
            ComponentName res = ComponentName.readFromParcel(reply);
            data.recycle();
            reply.recycle();
            return res;
        }

        ......
    }

参数service是一个Intent实例,它里面指定了要启动的服务的名称,就是前面我们所说的"shy.luo.ashmem.server"了。

参数caller是一个IApplicationThread实例,它是一个在主进程创建的一个Binder对象。在Android应用程序中,每一个进程都用一个ActivityThread实例来表示,而在ActivityThread类中,有一个成员变量mAppThread,它是一个ApplicationThread实例,实现了IApplicationThread接口,它的作用是用来辅助ActivityThread类来执行一些操作,这个我们在后面会看到它是如何用来启动服务的。

参数resolvedType是一个字符串,它表示service这个Intent的MIME类型,它是在解析Intent时用到的。在这个例子中,我们没有指定这个Intent 的MIME类型,因此,这个参数为null。

ActivityManagerProxy类的startService函数把这三个参数写入到data本地变量去,接着通过mRemote.transact函数进入到Binder驱动程序,然后Binder驱动程序唤醒正在等待Client请求的ActivityManagerService进程,最后进入到ActivityManagerService的startService函数中。

ActivityManagerService的startService函数的处理流程如下图所示:

点击查看大图

在这个序列图中,一共有20个步骤,下面说明每一步。

Step 1. ActivityManagerService.startService

这个函数定义在frameworks/base/services/java/com/android/server/am/ActivityManagerService.java文件中:

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

        ......

        public ComponentName startService(IApplicationThread caller, Intent service,
                String resolvedType) {      
              // Refuse possible leaked file descriptors
              if (service != null && service.hasFileDescriptors() == true) {
                  throw new IllegalArgumentException("File descriptors passed in Intent");
              }

              synchronized(this) {
                  final int callingPid = Binder.getCallingPid();
                  final int callingUid = Binder.getCallingUid();
                  final long origId = Binder.clearCallingIdentity();
                  ComponentName res = startServiceLocked(caller, service,
                      resolvedType, callingPid, callingUid);
                  Binder.restoreCallingIdentity(origId);
                  return res;
              }
        }

        ......

    }

这里的参数caller、service和resolvedType分别对应ActivityManagerProxy.startService传进来的三个参数。

Step 2. ActivityManagerService.startServiceLocked 这个函数同样定义在frameworks/base/services/java/com/android/server/am/ActivityManagerService.java文件中:

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

        ......

        ComponentName startServiceLocked(IApplicationThread caller,
                Intent service, String resolvedType,
                int callingPid, int callingUid) {
            synchronized(this) {
                ......

                ServiceLookupResult res =
                    retrieveServiceLocked(service, resolvedType,
                    callingPid, callingUid);

                ......

                ServiceRecord r = res.record;

                ......

                if (!bringUpServiceLocked(r, service.getFlags(), false)) {
                    return new ComponentName("!", "Service process is bad");
                }
                return r.name;
            }
        }

        ......

    }

函数首先通过retrieveServiceLocked来解析service这个Intent,就是解析前面我们在AndroidManifest.xml定义的Service标签的intent-filter相关内容,然后将解析结果放在res.record中,然后继续调用bringUpServiceLocked进一步处理。

Step 3. ActivityManagerService.bringUpServiceLocked 这个函数同样定义在frameworks/base/services/java/com/android/server/am/ActivityManagerService.java文件中:

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

        ......

        private final boolean bringUpServiceLocked(ServiceRecord r,
                        int intentFlags, boolean whileRestarting) {

            ......

            final String appName = r.processName;

            ......

            // Not running -- get it started, and enqueue this service record
            // to be executed when the app comes up.
            if (startProcessLocked(appName, r.appInfo, true, intentFlags,
                        "service", r.name, false) == null) {

                ......

                return false;
            }

            if (!mPendingServices.contains(r)) {
                mPendingServices.add(r);
            }

            return true;

        }

        ......

    }

这里的appName便是我们前面在AndroidManifest.xml文件定义service标签时指定的android:process属性值了,即".Server"。

接着调用startProcessLocked函数来创建一个新的进程,以便加载自定义的Service类。最后将这个ServiceRecord保存在成员变量mPendingServices列表中,后面会用到。

Step 4. ActivityManagerService.startProcessLocked

这个函数同样定义在frameworks/base/services/java/com/android/server/am/ActivityManagerService.java文件中:

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

        ......

        private final void startProcessLocked(ProcessRecord app,
                    String hostingType, String hostingNameStr) {

            ......

            try {

                ......

                int pid = Process.start("android.app.ActivityThread",
                                mSimpleProcessManagement ? app.processName : null, uid, uid,
                                gids, debugFlags, null);

                ......

                if (pid == 0 || pid == MY_PID) {

                    ......

                } else if (pid > 0) {
                    app.pid = pid;
                    app.removed = false;
                    synchronized (mPidsSelfLocked) {
                        this.mPidsSelfLocked.put(pid, app);
                        ......
                    }
                } else {

                    ......
                }

            } catch (RuntimeException e) {

                ......

            }

        }

        ......

    }

这里调用Process.start函数创建了一个新的进程,指定新的进程执行android.app.ActivityThread类。最后将表示这个新进程的ProcessRecord保存在mPidSelfLocked列表中,后面会用到。

Step 5. Process.start

这个函数定义在frameworks/base/core/java/android/os/Process.java文件中,这个函数我们就不看了,有兴趣的读者可以自己研究一下。在这个场景中,它就是新建一个进程,然后导入android.app.ActivityThread这个类,然后执行它的main函数。

Step 6. ActivityThread.main 这个函数定义在frameworks/base/core/java/android/app/ActivityThread.java文件中:

public final class ActivityThread {

        ......

        public static final void main(String[] args) {

            ......

            Looper.prepareMainLooper();

            ......

            ActivityThread thread = new ActivityThread();
            thread.attach(false);

            ......

            Looper.loop();

            ......

            thread.detach();

            ......
        }
    }

注意,执行到这里的时候,已经是在上一步创建的新进程里面了,即这里的进程是用来启动服务的,原来的主进程已经完成了它的命令,返回了。

前面我们提到,在Android应用程序中,每一个进程对应一个ActivityThread实例,所以,这个函数会创建一个thread实例,然后调用ActivityThread.attach函数进一步处理。

Step 7. ActivityThread.attach

这个函数定义在frameworks/base/core/java/android/app/ActivityThread.java文件中:

public final class ActivityThread {

        ......

        private final void attach(boolean system) {

            ......

            if (!system) {

                ......

                IActivityManager mgr = ActivityManagerNative.getDefault();
                try {
                    mgr.attachApplication(mAppThread);
                } catch (RemoteException ex) {
                }
            } else {

                ......

            }

            ......

        }

        ......

    }

从Step 6中,这里传进来的参数system为false。成员变量mAppThread是一个ApplicationThread实例,我们在前面已经描述过这个实例的作用,它是用来辅助ActivityThread来执行一些操作的。

调用ActivityManagerNative.getDefault函数得到ActivityManagerService的远程接口,即ActivityManagerProxy,接着调用它的attachApplication函数。

Step 8. ActivityManagerProxy.attachApplication 这个函数定义在frameworks/base/core/java/android/app/ActivityManagerNative.java文件中:

class ActivityManagerProxy implements IActivityManager
    {
        ......

        public void attachApplication(IApplicationThread app) throws RemoteException
        {
            Parcel data = Parcel.obtain();
            Parcel reply = Parcel.obtain();
            data.writeInterfaceToken(IActivityManager.descriptor);
            data.writeStrongBinder(app.asBinder());
            mRemote.transact(ATTACH_APPLICATION_TRANSACTION, data, reply, 0);
            reply.readException();
            data.recycle();
            reply.recycle();
        }

        ......

    }

这个函数主要是将新进程里面的IApplicationThread实例通过Binder驱动程序传递给ActivityManagerService。

Step 9. ActivityManagerService.attachApplication

这个函数定义在frameworks/base/services/java/com/android/server/am/ActivityManagerService.java文件中:

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

        ......

        public final void attachApplication(IApplicationThread thread) 
        {
            synchronized (this) {
                int callingPid = Binder.getCallingPid();
                final long origId = Binder.clearCallingIdentity();
                attachApplicationLocked(thread, callingPid);
                Binder.restoreCallingIdentity(origId);
            }
        }

        ......

    }

这里通过调用attachApplicationLocked函数进一步处理。

Step 10. ActivityManagerService.attachApplicationLocked

这个函数定义在frameworks/base/services/java/com/android/server/am/ActivityManagerService.java文件中:

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

        ......

        private final boolean attachApplicationLocked(IApplicationThread thread,
                int pid) {
            // Find the application record that is being attached...  either via
            // the pid if we are running in multiple processes, or just pull the
            // next app record if we are emulating process with anonymous threads.
            ProcessRecord app;
            if (pid != MY_PID && pid >= 0) {
                synchronized (mPidsSelfLocked) {
                    app = mPidsSelfLocked.get(pid);
                }
            } else if (mStartingProcesses.size() > 0) {
                app = mStartingProcesses.remove(0);
                app.setPid(pid);
            } else {
                app = null;
            }

            ......


            String processName = app.processName;

            ......

            app.thread = thread;

            ......

            boolean badApp = false;

            ......

            // Find any services that should be running in this process...
            if (!badApp && mPendingServices.size() > 0) {
                ServiceRecord sr = null;
                try {
                    for (int i=0; i<mPendingServices.size(); i++) {
                        sr = mPendingServices.get(i);
                        if (app.info.uid != sr.appInfo.uid
                            || !processName.equals(sr.processName)) {
                                continue;
                        }

                        mPendingServices.remove(i);
                        i--;
                        realStartServiceLocked(sr, app);
                        didSomething = true;
                    }
                } catch (Exception e) {

                    ......

                }
            }

            ......

            return true;
        }

        ......

    }

回忆一下在上面的Step 4中,以新进程的pid值作为key值保存了一个ProcessRecord在mPidsSelfLocked列表中,这里先把它取出来,存放在本地变量app中,并且将app.processName保存在本地变量processName中。

再回忆一下在上面的Step 3中,在成员变量mPendingServices中,保存了一个ServiceRecord,这里通过进程uid和进程名称将它找出来,然后通过realStartServiceLocked函数来进一步处理。

Step 11. ActivityManagerService.realStartServiceLocked 这个函数定义在frameworks/base/services/java/com/android/server/am/ActivityManagerService.java文件中:

class ActivityManagerProxy implements IActivityManager
    {
        ......

        private final void realStartServiceLocked(ServiceRecord r,
                ProcessRecord app) throws RemoteException {

            ......

            r.app = app;

            ......

            try {

                ......

                app.thread.scheduleCreateService(r, r.serviceInfo);

                ......

            } finally {

                ......

            }

            ......

        }

        ......

    }

这里的app.thread是一个ApplicationThread对象的远程接口,它是在上面的Step 6创建ActivityThread对象时作为ActivityThread对象的成员变量同时创建的,然后在Step 9中传过来的。然后调用这个远程接口的scheduleCreateService函数回到原来的ActivityThread对象中执行启动服务的操作。

Step 12. ApplicationThreadProxy.scheduleCreateService

这个函数定义在frameworks/base/core/java/android/app/ApplicationThreadNative.java文件中:

class ApplicationThreadProxy implements IApplicationThread {

        ......

        public final void scheduleCreateService(IBinder token, ServiceInfo info)
                    throws RemoteException {
            Parcel data = Parcel.obtain();
            data.writeInterfaceToken(IApplicationThread.descriptor);
            data.writeStrongBinder(token);
            info.writeToParcel(data, 0);
            mRemote.transact(SCHEDULE_CREATE_SERVICE_TRANSACTION, data, null,
                IBinder.FLAG_ONEWAY);
            data.recycle();
        }

        ......

    }

这里通过Binder驱动程序回到新进程的ApplicationThread对象中去执行scheduleCreateService函数。

Step 13. ApplicationThread.scheduleCreateService

这个函数定义在frameworks/base/core/java/android/app/ActivityThread.java文件中:

public final class ActivityThread {

        ......

        private final class ApplicationThread extends ApplicationThreadNative {

            ......

            public final void scheduleCreateService(IBinder token,
            ServiceInfo info) {
                CreateServiceData s = new CreateServiceData();
                s.token = token;
                s.info = info;

                queueOrSendMessage(H.CREATE_SERVICE, s);
            }

            ......

        }

        ......

    }

这里调用ActivityThread的queueOrSendMessage将一个CreateServiceData数据放到消息队列中去,并且分开这个消息。注意,这里已经是在上面Step 4创建的新进程中执行了。

Step 14. ActivityThread.queueOrSendMessage

这个函数定义在frameworks/base/core/java/android/app/ActivityThread.java文件中:

public final class ActivityThread {

        ......

        private final void queueOrSendMessage(int what, Object obj) {
            queueOrSendMessage(what, obj, 0, 0);
        }

        private final void queueOrSendMessage(int what, Object obj, int arg1, int arg2) {
            synchronized (this) {
                ......
                Message msg = Message.obtain();
                msg.what = what;
                msg.obj = obj;
                msg.arg1 = arg1;
                msg.arg2 = arg2;
                mH.sendMessage(msg);
            }
        }

        ......

    }

这里调用成员变量mH的sendMessage函数进行消息分发。这里的mH的类型为H,它继承于Handler类。

Step 15. H.sendMessage

这个函数继承于Handle类的sendMessage函数中,定义在frameworks/base/core/java/android/os/Handler.java文件中。这个函数我们就不看了,有兴趣的读者可以自己研究一下。消息分发以后,就进入到H.handleMessage函数进行处理了。

Step 16. H.handleMessage

这个函数定义在frameworks/base/core/java/android/app/ActivityThread.java文件中:

public final class ActivityThread {

        ......

        private final class H extends Handler {

            ......

            public void handleMessage(Message msg) {

                ......

                switch (msg.what) {

                    ......

                    case CREATE_SERVICE:
                        handleCreateService((CreateServiceData)msg.obj);
                        break;

                    ......
                }

                ......

            }

            ......

        }

        ......

    }

这里要处理的消息是CREATE_SERVICE,它调用ActivityThread类的handleCreateService成员函数进一步处理。

Step 17. ActivityThread.handleCreateService

这个函数定义在frameworks/base/core/java/android/app/ActivityThread.java文件中:

public final class ActivityThread {

        ......

        private final void handleCreateService(CreateServiceData data) {
            // If we are getting ready to gc after going to the background, well
            // we are back active so skip it.
            unscheduleGcIdler();

            LoadedApk packageInfo = getPackageInfoNoCheck(
                data.info.applicationInfo);
            Service service = null;
            try {
                java.lang.ClassLoader cl = packageInfo.getClassLoader();
                service = (Service) cl.loadClass(data.info.name).newInstance();
            } catch (Exception e) {
                if (!mInstrumentation.onException(service, e)) {
                    throw new RuntimeException(
                        "Unable to instantiate service " + data.info.name
                        + ": " + e.toString(), e);
                }
            }

            try {
                if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name);

                ContextImpl context = new ContextImpl();
                context.init(packageInfo, null, this);

                Application app = packageInfo.makeApplication(false, mInstrumentation);
                context.setOuterContext(service);
                service.attach(context, this, data.info.name, data.token, app,
                    ActivityManagerNative.getDefault());
                service.onCreate();
                mServices.put(data.token, service);
                try {
                    ActivityManagerNative.getDefault().serviceDoneExecuting(
                        data.token, 0, 0, 0);
                } catch (RemoteException e) {
                    // nothing to do.
                }

            } catch (Exception e) {
                if (!mInstrumentation.onException(service, e)) {
                    throw new RuntimeException(
                        "Unable to create service " + data.info.name
                        + ": " + e.toString(), e);
                }
            }
        }

        ......

    }

这里的data.info.name就是自定义的服务类shy.luo.ashmem.Server了。

Step 18. ClassLoader.loadClass

这一步实现在上面的ActivityThread.handleCreateService函数中:

java.lang.ClassLoader cl = packageInfo.getClassLoader();
    service = (Service) cl.loadClass(data.info.name).newInstance();

Step 19. Obtain Service

这一步也是实现在上面的ActivityThread.handleCreateService函数中。上面通过ClassLoader.loadClass来导入自定义的服务类shy.luo.ashmem.Server并且创建它的一个实例后,就通过强制类型转换得到一个Service类实例。前面我们说过,自己的服务类必须要继承于Service类,这里就体现出来了为什么要这样做了。

Step 20. Service.onCreate

这一步继续实现在上面的ActivityThread.handleCreateService函数中:

service.onCreate();

因为这里的service实际上是一个shy.luo.ashmem.Server类实例,因此,这里就是执行shy.luo.ashmem.Server类的onCreate函数了:

public class Server extends Service {

        ......

        @Override
        public void onCreate() {
            ......

        }

        ......
    }

至此,这个自定义的服务就启动起来了。

这样,Android系统在新进程中启动服务的过程就分析完成了,虽然很复杂,但是条理很清晰。它通过三次Binder进程间通信完成了服务的启动过程,分别是:

一. Step 1至Step 7,从主进程调用到ActivityManagerService进程中,完成新进程的创建;

二. Step 8至Step 11,从新进程调用到ActivityManagerService进程中,获取要在新进程启动的服务的相关信息;

三. Step 12至Step 20,从ActivityManagerService进程又回到新进程中,最终将服务启动起来。

学习完Android系统在新进程中启动服务的过程后,希望读者对Android系统的Service有一个深刻的理解。在编写Android应用程序的时候,尽量把一些计算型的逻辑以Service在形式来实现,使得这些耗时的计算能在一个独立的进程中进行,这样就能保持主进程流畅地响应界面事件,提高用户体验。

 相关推荐

刘强东夫妇:“移民美国”传言被驳斥

京东创始人刘强东和其妻子章泽天最近成为了互联网舆论关注的焦点。有关他们“移民美国”和在美国购买豪宅的传言在互联网上广泛传播。然而,京东官方通过微博发言人发布的消息澄清了这些传言,称这些言论纯属虚假信息和蓄意捏造。

发布于:6月以前  |  808次阅读  |  详细内容 »

博主曝三大运营商,将集体采购百万台华为Mate60系列

日前,据博主“@超能数码君老周”爆料,国内三大运营商中国移动、中国电信和中国联通预计将集体采购百万台规模的华为Mate60系列手机。

发布于:6月以前  |  770次阅读  |  详细内容 »

ASML CEO警告:出口管制不是可行做法,不要“逼迫中国大陆创新”

据报道,荷兰半导体设备公司ASML正看到美国对华遏制政策的负面影响。阿斯麦(ASML)CEO彼得·温宁克在一档电视节目中分享了他对中国大陆问题以及该公司面临的出口管制和保护主义的看法。彼得曾在多个场合表达了他对出口管制以及中荷经济关系的担忧。

发布于:6月以前  |  756次阅读  |  详细内容 »

抖音中长视频App青桃更名抖音精选,字节再发力对抗B站

今年早些时候,抖音悄然上线了一款名为“青桃”的 App,Slogan 为“看见你的热爱”,根据应用介绍可知,“青桃”是一个属于年轻人的兴趣知识视频平台,由抖音官方出品的中长视频关联版本,整体风格有些类似B站。

发布于:6月以前  |  648次阅读  |  详细内容 »

威马CDO:中国每百户家庭仅17户有车

日前,威马汽车首席数据官梅松林转发了一份“世界各国地区拥车率排行榜”,同时,他发文表示:中国汽车普及率低于非洲国家尼日利亚,每百户家庭仅17户有车。意大利世界排名第一,每十户中九户有车。

发布于:6月以前  |  589次阅读  |  详细内容 »

研究发现维生素 C 等抗氧化剂会刺激癌症生长和转移

近日,一项新的研究发现,维生素 C 和 E 等抗氧化剂会激活一种机制,刺激癌症肿瘤中新血管的生长,帮助它们生长和扩散。

发布于:6月以前  |  449次阅读  |  详细内容 »

苹果据称正引入3D打印技术,用以生产智能手表的钢质底盘

据媒体援引消息人士报道,苹果公司正在测试使用3D打印技术来生产其智能手表的钢质底盘。消息传出后,3D系统一度大涨超10%,不过截至周三收盘,该股涨幅回落至2%以内。

发布于:7月以前  |  446次阅读  |  详细内容 »

千万级抖音网红秀才账号被封禁

9月2日,坐拥千万粉丝的网红主播“秀才”账号被封禁,在社交媒体平台上引发热议。平台相关负责人表示,“秀才”账号违反平台相关规定,已封禁。据知情人士透露,秀才近期被举报存在违法行为,这可能是他被封禁的部分原因。据悉,“秀才”年龄39岁,是安徽省亳州市蒙城县人,抖音网红,粉丝数量超1200万。他曾被称为“中老年...

发布于:6月以前  |  445次阅读  |  详细内容 »

亚马逊股东起诉公司和贝索斯,称其在购买卫星发射服务时忽视了 SpaceX

9月3日消息,亚马逊的一些股东,包括持有该公司股票的一家养老基金,日前对亚马逊、其创始人贝索斯和其董事会提起诉讼,指控他们在为 Project Kuiper 卫星星座项目购买发射服务时“违反了信义义务”。

发布于:6月以前  |  444次阅读  |  详细内容 »

苹果上线AppsbyApple网站,以推广自家应用程序

据消息,为推广自家应用,苹果现推出了一个名为“Apps by Apple”的网站,展示了苹果为旗下产品(如 iPhone、iPad、Apple Watch、Mac 和 Apple TV)开发的各种应用程序。

发布于:6月以前  |  442次阅读  |  详细内容 »

特斯拉美国降价引发投资者不满:“这是短期麻醉剂”

特斯拉本周在美国大幅下调Model S和X售价,引发了该公司一些最坚定支持者的不满。知名特斯拉多头、未来基金(Future Fund)管理合伙人加里·布莱克发帖称,降价是一种“短期麻醉剂”,会让潜在客户等待进一步降价。

发布于:6月以前  |  441次阅读  |  详细内容 »

光刻机巨头阿斯麦:拿到许可,继续对华出口

据外媒9月2日报道,荷兰半导体设备制造商阿斯麦称,尽管荷兰政府颁布的半导体设备出口管制新规9月正式生效,但该公司已获得在2023年底以前向中国运送受限制芯片制造机器的许可。

发布于:6月以前  |  437次阅读  |  详细内容 »

马斯克与库克首次隔空合作:为苹果提供卫星服务

近日,根据美国证券交易委员会的文件显示,苹果卫星服务提供商 Globalstar 近期向马斯克旗下的 SpaceX 支付 6400 万美元(约 4.65 亿元人民币)。用于在 2023-2025 年期间,发射卫星,进一步扩展苹果 iPhone 系列的 SOS 卫星服务。

发布于:6月以前  |  430次阅读  |  详细内容 »

𝕏(推特)调整隐私政策,可拿用户发布的信息训练 AI 模型

据报道,马斯克旗下社交平台𝕏(推特)日前调整了隐私政策,允许 𝕏 使用用户发布的信息来训练其人工智能(AI)模型。新的隐私政策将于 9 月 29 日生效。新政策规定,𝕏可能会使用所收集到的平台信息和公开可用的信息,来帮助训练 𝕏 的机器学习或人工智能模型。

发布于:6月以前  |  428次阅读  |  详细内容 »

荣耀CEO谈华为手机回归:替老同事们高兴,对行业也是好事

9月2日,荣耀CEO赵明在采访中谈及华为手机回归时表示,替老同事们高兴,觉得手机行业,由于华为的回归,让竞争充满了更多的可能性和更多的魅力,对行业来说也是件好事。

发布于:6月以前  |  423次阅读  |  详细内容 »

AI操控无人机能力超越人类冠军

《自然》30日发表的一篇论文报道了一个名为Swift的人工智能(AI)系统,该系统驾驶无人机的能力可在真实世界中一对一冠军赛里战胜人类对手。

发布于:7月以前  |  423次阅读  |  详细内容 »

AI生成的蘑菇科普书存在可致命错误

近日,非营利组织纽约真菌学会(NYMS)发出警告,表示亚马逊为代表的电商平台上,充斥着各种AI生成的蘑菇觅食科普书籍,其中存在诸多错误。

发布于:7月以前  |  420次阅读  |  详细内容 »

社交媒体平台𝕏计划收集用户生物识别数据与工作教育经历

社交媒体平台𝕏(原推特)新隐私政策提到:“在您同意的情况下,我们可能出于安全、安保和身份识别目的收集和使用您的生物识别信息。”

发布于:7月以前  |  411次阅读  |  详细内容 »

国产扫地机器人热销欧洲,国产割草机器人抢占欧洲草坪

2023年德国柏林消费电子展上,各大企业都带来了最新的理念和产品,而高端化、本土化的中国产品正在不断吸引欧洲等国际市场的目光。

发布于:6月以前  |  406次阅读  |  详细内容 »

罗永浩吐槽iPhone15和14不会有区别,除了序列号变了

罗永浩日前在直播中吐槽苹果即将推出的 iPhone 新品,具体内容为:“以我对我‘子公司’的了解,我认为 iPhone 15 跟 iPhone 14 不会有什么区别的,除了序(列)号变了,这个‘不要脸’的东西,这个‘臭厨子’。

发布于:6月以前  |  398次阅读  |  详细内容 »
 目录