Surface的理解

news/2024/11/15 2:08:44/

1 Surface創建

既然requestLayout内部是通过给主线程Handler发送任务消息并在Vsync同步信号返回后执行Runable。那我们就继续看看Runable内部执行的

// ========== android.view.ViewRootImpl ===========void doTraversal() {if (mTraversalScheduled) {mTraversalScheduled = false;//移除同步屏障,已经开始执行View绘制任务,允许后续继续执行同步消息mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);...//执行遍历视图树操作performTraversals();...}
}private void performTraversals() {//实际上就是最顶层的DecorViewfinal View host = mView;...//关键代码,检查Surface图像缓冲区队列建立连接relayoutResult = relayoutWindow(...);    ...//window的宽高    if (mWidth != frame.width() || mHeight != frame.height()) {mWidth = frame.width();mHeight = frame.height();}    ...// 最外层的测量宽高   int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width);int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height);//测量尺寸,内部执行View.measure()方法performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);...//布局排版,内部执行View.layout()方法performLayout(lp, mWidth, mHeight);   ...//开始绘制View,内部执行View.draw()方法performDraw();...
}

doTraversal方法做了些什么。视图绘制请求最终都在performTraversals方法内,依次执行measurelayoutdraw等方法。而在这些操作调用之前,会最先调用了一个relayoutWindow方法,这里先以此展开继续分析。

 java层 SurfaceControl创建

// ============== android.view.ViewRootImpl ================
final IWindowSession mWindowSession;//Surface的句柄类,默认构造为空对象,只是一个指针,没有实际引用
private final SurfaceControl mSurfaceControl = new SurfaceControl();
private SurfaceControl mBlastSurfaceControl = new SurfaceControl();
//默认构造函数是个空对象,只是一个指针,没有实际引用
public final Surface mSurface = new Surface();private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,...)...{...//跨进程Binder代理调用,内部创建了native的SurfaceControl,并赋值给jave层内部变量对象引用地址int relayoutResult = mWindowSession.relayout(mWindow, mSeq, params,(int) (mView.getMeasuredWidth() * appScale + 0.5f),(int) (mView.getMeasuredHeight() * appScale + 0.5f),..., mSurfaceControl, mSurfaceSize, mBlastSurfaceControl);...if (mSurfaceControl.isValid()) {  //此时mSurfaceControl已经有实际引用...//从SurfaceControl拷贝native Surface对象引用    mSurface.copyFrom(mSurfaceControl);...}}// ============ android.view.SurfaceControl =================public final class SurfaceControl implements Parcelable {// native层的SurfaceControl 的对象引用地址public long mNativeObject;// 默认实现为空对象public SurfaceControl() {}public boolean isValid() {return mNativeObject != 0;}
}// android.view.Surface
public class Surface implements Parcelable {//默认为空对象public Surface() {}
}

relayoutWindow内部通过Binder机制跨进程调用了system_service进程内的Session.relayout方法,并传入了mSurfaceControl对象。

紧接着就开始判断该对象内部的mNativeObject变量不为0,然后让mSurface从该对象内拷贝赋值。

mSurfaceControl默认构造函数又为空实现

// ============== com.android.server.wm.Session =======================
class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {@Overridepublic int relayout(IWindow window, ...SurfaceControl outSurfaceControl, ... , Point outSurfaceSizeSurfaceControl outBLASTSurfaceControl) {1 int res = mService.relayoutWindow(this, window, ... , outSurfaceControl, outSurfaceSize,outBLASTSurfaceControl);...return res;}
}//================== com.android.server.wm.WindowManagerService ===================public int relayoutWindow(Session session, IWindow client, ... ,SurfaceControl outSurfaceControl, ... , Point outSurfaceSize,SurfaceControl outBLASTSurfaceControl) {...//获取addWindow时创建的WindowState对象final WindowState win = windowForClientLocked(session, client, false);...WindowStateAnimator winAnimator = win.mWinAnimator;...int result = 0;    ...//判断是否需要重新建立关联的SurfaceControl    final boolean shouldRelayout = viewVisibility == View.VISIBLE &&(win.mActivityRecord == null || win.mAttrs.type == TYPE_APPLICATION_STARTING|| win.mActivityRecord.isClientVisible());...//窗口内第一次启动    if(shouldRelayout){    2 //创建native的SurfaceControlresult = createSurfaceControl(outSurfaceControl, outBLASTSurfaceControl,result, win, winAnimator);}else{...}...return result    
}final WindowState windowForClientLocked(Session session, IBinder client, boolean throwOnError) {//获取当前App进程的View与system_service进程关联,addWindow时创建的WindowState,//其持有与SurfaceFLinger连接的ClientWindowState win = mWindowMap.get(client);...return win;    
}

总结 1 Session作为一个中间类,会转交给WindowManagerService.relayoutWindow处理。

而且在relayoutWindow中,传入了一个outSurfaceControl参数

2调用了createSurfaceControl方法

//================== com.android.server.wm.WindowManagerService ===================private int createSurfaceControl(SurfaceControl outSurfaceControl,SurfaceControl outBLASTSurfaceControl, int result,WindowState win, WindowStateAnimator winAnimator) {...    WindowSurfaceController surfaceController = winAnimator.createSurfaceLocked(win.mAttrs.type, win.mOwnerUid);...//内部调用copyFrom方法,即拷贝到outSurfaceControlsurfaceController.getSurfaceControl(outSurfaceControl);surfaceController.getBLASTSurfaceControl(outBLASTSurfaceControl);    
}

getSurfaceControl方法

// ============ com.android.server.wm.WindowSurfaceController ====================
class WindowSurfaceController {SurfaceControl mSurfaceControl;WindowSurfaceController(String name, int w, int h, ...,WindowStateAnimator animator,...) {final WindowState win = animator.mWin;...//暂且忽略这一串Builder参数,Window请求Surfacefinal SurfaceControl.Builder b = win.makeSurface().setParent(win.getSurfaceControl()).setName(name).setBufferSize(w, h).setFormat(format).setFlags(flags).setMetadata(METADATA_WINDOW_TYPE, windowType).setMetadata(METADATA_OWNER_UID, ownerUid).setCallsite("WindowSurfaceController");...mSurfaceControl = b.build();...}void getSurfaceControl(SurfaceControl outSurfaceControl) {outSurfaceControl.copyFrom(mSurfaceControl, "WindowSurfaceController.getSurfaceControl");}void getBLASTSurfaceControl(SurfaceControl outSurfaceControl) {if (mBLASTSurfaceControl != null) {outSurfaceControl.copyFrom(mBLASTSurfaceControl, "WindowSurfaceController.getBLASTSurfaceControl");}}
}

getSurfaceControl实际上就是从WindowSurfaceController内部拷贝了一份SurfaceControl,并赋值给传入的outSurfaceControl

而且在WindowSurfaceController的构造函数内,通过SurfaceControl.Builder.build方法请求并创建了这个原始SurfaceControl

// ============ android.view.SurfaceControl ====================
public final class SurfaceControl implements Parcelable {public static class Builder {private SurfaceSession mSession;public SurfaceControl build() {return new SurfaceControl(mSession, mName, mWidth, mHeight,...);}}//native 的 SurfaceControl 对象引用地址public long mNativeObject;//空实现public SurfaceControl() {}private SurfaceControl(SurfaceSession session, String name, int w, int h, int format, int flags,SurfaceControl parent, SparseIntArray metadata, WeakReference<View> localOwnerView,String callsite) ... {...//关键代码    mNativeObject = nativeCreate(session, name, w, h, format, flags,parent != null ? parent.mNativeObject : 0, metaParcel);...}//native方法,实际创建了native层的Surfaceprivate static native long nativeCreate(SurfaceSession session, ... ) ...;private static native long nativeCopyFromSurfaceControl(long nativeObject);private static native long nativeGetHandle(long nativeObject);public void copyFrom(@NonNull SurfaceControl other, String callsite) {...//实际是复制了这个mNativeObject对象引用assignNativeObject(nativeCopyFromSurfaceControl(other.mNativeObject), callsite);}private void assignNativeObject(long nativeObject, String callsite) {...mNativeObject = nativeObject;mNativeHandle = mNativeObject != 0 ? nativeGetHandle(nativeObject) : 0;}
}


native层 SurfaceControl创建

// ========== frameworks/base/core/jni/android_view_SurfaceControl.cpp ===============static jlong nativeCreate(JNIEnv* env, jclass clazz, jobject sessionObj,jstring nameStr, jint w, jint h, jint format, jint flags, jlong parentObject,jobject metadataParcel) {...sp<SurfaceComposerClient> client;if (sessionObj != NULL) {//SurfaceSession不为空的情况,也就是前面建立连接时创建的SurfaceComposerClientclient = android_view_SurfaceSession_getClient(env, sessionObj);} else {client = SurfaceComposerClient::getDefault();}SurfaceControl *parent = reinterpret_cast<SurfaceControl*>(parentObject);sp<SurfaceControl> surface;LayerMetadata metadata;Parcel* parcel = parcelForJavaObject(env, metadataParcel);if (parcel && !parcel->objectsCount()) {status_t err = metadata.readFromParcel(parcel);...}   //通过SurfaceComposerClient创建native SurfaceControlstatus_t err = client->createSurfaceChecked(String8(name.c_str()), w, h, format, &surface, flags, parent, std::move(metadata));...surface->incStrong((void *)nativeCreate);return reinterpret_cast<jlong>(surface.get());
}// =========== frameworks/base/core/jni/android_view_SurfaceSession.cpp =================sp<SurfaceComposerClient> android_view_SurfaceSession_getClient(JNIEnv* env, jobject surfaceSessionObj) {return reinterpret_cast<SurfaceComposerClient*>(env->GetLongField(surfaceSessionObj, gSurfaceSessionClassInfo.mNativeClient));
}

其内部是返回了一个native的SurfaceControl对象引用地址。

随后通过SurfaceComposerClient.createSurfaceChecked创建这个native层的SurfaceControl对象

// ================= frameworks/native/libs/gui/SurfaceComposerClient.cpp ===================sp<ISurfaceComposerClient>  mClient;status_t SurfaceComposerClient::createSurfaceChecked(...,sp<SurfaceControl>* outSurface, ...,SurfaceControl* parent, LayerMetadata metadata,...) {sp<SurfaceControl> sur;status_t err = mStatus;...if (mStatus == NO_ERROR) {sp<IBinder> handle;sp<IGraphicBufferProducer> gbp;...// 跨进程Binder代理调用Client的createSurface方法,// 内部并最终调用到SurfaceFlinger.createLayer,创建Layer// 传入了两个代理类对象引用err = mClient->createSurface(...&handle,&gbp,...);if (outTransformHint) {*outTransformHint = transformHint;}...if (err == NO_ERROR) {//创建一个新的SurfaceControl对象,并将引用赋值给外部传入的SurfaceControl*outSurface = new SurfaceControl(this, handle, gbp, transformHint);}}return err;
}

Client.createSurface最终会调用到SurfaceFlinger.createLayer方法创建LayerLayerSurfaceFlinger的基本操作单元。

// =========== frameworks/native/services/surfaceflinger/Client.cpp ==================sp<SurfaceFlinger> mFlinger;status_t Client::createSurface(const String8& name, uint32_t w, uint32_t h, PixelFormat format,uint32_t flags, const sp<IBinder>& parentHandle,LayerMetadata metadata, sp<IBinder>* handle,sp<IGraphicBufferProducer>* gbp, uint32_t* outTransformHint) {// We rely on createLayer to check permissions.return mFlinger->createLayer(name, this, w, h, format, flags, std::move(metadata), handle, gbp,parentHandle, nullptr, outTransformHint);
}// ================== frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp ==================status_t SurfaceFlinger::createLayer(const String8& name, const sp<Client>& client, uint32_t w,uint32_t h, PixelFormat format, uint32_t flags,LayerMetadata metadata, sp<IBinder>* handle,sp<IGraphicBufferProducer>* gbp,const sp<IBinder>& parentHandle, const sp<Layer>& parentLayer,uint32_t* outTransformHint) {status_t result = NO_ERROR;sp<Layer> layer;//根据flags创建不同的Layerswitch (flags & ISurfaceComposerClient::eFXSurfaceMask) {case ISurfaceComposerClient::eFXSurfaceBufferQueue://常用的BufferQueueLayerresult = createBufferQueueLayer(client, std::move(uniqueName), w, h, flags,std::move(metadata), format, handle, gbp, &layer);break;//还有好几种Layer    ...}...//保存新创建的Layer    mInterceptor->saveSurfaceCreation(layer);return result;
}
// ================ frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp ==================status_t SurfaceFlinger::createBufferQueueLayer(const sp<Client>& client, std::string name,uint32_t w, uint32_t h, uint32_t flags,LayerMetadata metadata, PixelFormat& format,sp<IBinder>* handle,sp<IGraphicBufferProducer>* gbp,sp<Layer>* outLayer) {sp<BufferQueueLayer> layer;...//通过工厂模式创建BufferQueueLayerlayer = getFactory().createBufferQueueLayer(args);...//设置一些Layer内部的属性status_t err = layer->setDefaultBufferProperties(w, h, format);if (err == NO_ERROR) {// 注意这两个对象引用,是会传到外部SurfaceControl构造函数的*handle = layer->getHandle();*gbp = layer->getProducer();*outLayer = layer;}  return err;
}

SurfaceFlinger创建出Layer后,引出了 IGraphicBufferProducerIBinder的代理类,并传入到SurfaceControl的构造函数。

// =========== frameworks/native/libs/gui/SurfaceControl.cpp ===============
SurfaceControl::SurfaceControl(const sp<SurfaceComposerClient>& client, const sp<IBinder>& handle,const sp<IGraphicBufferProducer>& gbp,uint32_t transform): mClient(client),mHandle(handle),mGraphicBufferProducer(gbp),mTransformHint(transform) {}

也就是说SurfaceFlinger中创建的Layer是通过其内部的Producer代理对象Handle代理对象SurfaceControl进行关联

就以此为切入点,来看下getProducergetHandle究竟获取到了什么?

// ========= frameworks/native/services/surfaceflinger/Layer.cpp =================sp<IBinder> Layer::getHandle() {...return new Handle(mFlinger, this);
}class Handle : public BBinder, public LayerCleaner {public:Handle(const sp<SurfaceFlinger>& flinger, const sp<Layer>& layer): LayerCleaner(flinger, layer), owner(layer) {}wp<Layer> owner;
};// ============== frameworks/native/services/surfaceflinger/BufferQueueLayer.cpp =================sp<IGraphicBufferProducer> BufferQueueLayer::getProducer() const {return mProducer;
}

getHandle是新创建了一个Handle对象,属于BBinder实现类,内部包含了SurfaceFlingerLayer的引用,作为Surface操作Layer句柄类。

getProducer返回的内部对象引用又是什么呢?我们继续来看其构造函数

BufferQueueLayer是继承自BufferLayerBufferLayer继承自LayerLayer又是继承自RefBase

// ============= frameworks/native/services/surfaceflinger/BufferQueueLayer.h ==============
class BufferQueueLayer : public BufferLayer {private {sp<IGraphicBufferProducer> mProducer;}...
}// ============== frameworks/native/services/surfaceflinger/BufferLayer.h ============
class BufferLayer : public Layer {...
}// ============== frameworks/native/services/surfaceflinger/Layer.h ================
class Layer : public virtual RefBase, compositionengine::LayerFE {...
}// ============== frameworks/native/services/surfaceflinger/BufferQueueLayer.cpp ================void BufferQueueLayer::onFirstRef() {BufferLayer::onFirstRef();// Creates a custom BufferQueue for SurfaceFlingerConsumer to use//创建了一个生产者和消费者模型,sp<IGraphicBufferProducer> producer; //生产者缓冲区sp<IGraphicBufferConsumer> consumer; //消费者缓冲区//创建了一个BufferQueueCore管理BufferQueue队列,并以此为核心创建赋值生产者与消费者mFlinger->getFactory().createBufferQueue(&producer, &consumer, true);mProducer = mFlinger->getFactory().createMonitoredProducer(producer, mFlinger, this);mConsumer = mFlinger->getFactory().createBufferLayerConsumer(consumer, mFlinger->getRenderEngine(),mTextureName, this);...// BufferQueueCore::mMaxDequeuedBufferCount is default to 1if (!mFlinger->isLayerTripleBufferingDisabled()) {//如果没有开启3级缓冲区,则设置为2级缓冲区mProducer->setMaxDequeuedBufferCount(2);}
}

既然是RefBase的子类,在第一次获取到强引用时就会触发onFirstRef方法,其在内部创建了一个基于BufferQueue生产者与消费者模型

而通过getProducer方法获取到的正是其作为生产者BufferQueueProducer,用于从BufferQueueCore中获取图像缓冲区buffer对象,交由客户端写入显示内容。

// ============ frameworks/native/libs/gui/BufferQueue.cpp ===============// getFactory().createBufferQueue
// 最终会调用到BufferQueue.createBufferQueue方法
void BufferQueue::createBufferQueue(sp<IGraphicBufferProducer>* outProducer,sp<IGraphicBufferConsumer>* outConsumer,bool consumerIsSurfaceFlinger) {LOG_ALWAYS_FATAL_IF(outProducer == nullptr,"BufferQueue: outProducer must not be NULL");LOG_ALWAYS_FATAL_IF(outConsumer == nullptr,"BufferQueue: outConsumer must not be NULL");//图形缓冲区队列的中枢类sp<BufferQueueCore> core(new BufferQueueCore());...//用core类创建生产者,用于从队列中获取缓冲区并写入绘制内容//返回为Binder代理类    sp<IGraphicBufferProducer> producer(new BufferQueueProducer(core, consumerIsSurfaceFlinger));...//用core类创建消费者,用于从队列中获取缓冲区数据,并交由Surfaceflinger处理//返回为Binder代理类sp<IGraphicBufferConsumer> consumer(new BufferQueueConsumer(core));...*outProducer = producer;*outConsumer = consumer;
}

至此,native层SurfaceControl创建就出来了,通过BufferQueueProducer的Binder代理类,和SurfaceFlinger创建的Layer进行关联。

并最终将native层的SurfaceControl对象引用,赋值给java层的SurfaceControl

 java层 Surface创建

接下来就是通过Surface.copyFrom对这个新的SurfaceControl拷贝出可用的Surface了。

// ============= android.view.Surface ================public class Surface implements Parcelable {long mNativeObject; // package scope only for SurfaceControl accessprivate static native long nativeGetFromSurfaceControl(long surfaceObject,long surfaceControlNativeObject);private static native void nativeRelease(long nativeObject);public void copyFrom(SurfaceControl other) {...long surfaceControlPtr = other.mNativeObject;...//从SurfaceControl内创建Surfacelong newNativeObject = nativeGetFromSurfaceControl(mNativeObject, surfaceControlPtr);synchronized (mLock) {if (newNativeObject == mNativeObject) {return;}if (mNativeObject != 0) {nativeRelease(mNativeObject);}setNativeObjectLocked(newNativeObject);}}private void setNativeObjectLocked(long ptr) {if (mNativeObject != ptr) {...mNativeObject = ptr;mGenerationId += 1;if (mHwuiContext != null) {mHwuiContext.updateSurface();}}}
}

native层 Surface创建

Surface.copyFrom方法内,同样也是通过native方法,赋值native对象引用地址。

通过调用native层的SurfaceControl.generateSurfaceLocked方法创建了native层Surface

然后将native层Surface的对象引用指针,赋值给java层SurfacemNativeObject

// ============== frameworks/base/core/jni/android_view_Surface.cpp ====================static jlong nativeGetFromSurfaceControl(JNIEnv* env, jclass clazz,jlong nativeObject,jlong surfaceControlNativeObj) {Surface* self(reinterpret_cast<Surface *>(nativeObject));sp<SurfaceControl> ctrl(reinterpret_cast<SurfaceControl *>(surfaceControlNativeObj));// If the underlying IGBP's are the same, we don't need to do anything.if (self != nullptr &&IInterface::asBinder(self->getIGraphicBufferProducer()) ==IInterface::asBinder(ctrl->getIGraphicBufferProducer())) {//实际持有的Producer代理对象是同一个,不做任何处理return nativeObject;}//通过SurfaceControl创建native层的Surfacesp<Surface> surface(ctrl->getSurface());if (surface != NULL) {surface->incStrong(&sRefBaseOwner);}//返回native层surface对象的引用地址return reinterpret_cast<jlong>(surface.get());
}// =========== frameworks/native/libs/gui/SurfaceControl.cpp ==================mutable sp<Surface>         mSurfaceData;sp<Surface> SurfaceControl::getSurface() const
{Mutex::Autolock _l(mLock);if (mSurfaceData == nullptr) {return generateSurfaceLocked();}return mSurfaceData;
}sp<Surface> SurfaceControl::generateSurfaceLocked() const
{// mGraphicBufferProducer就是Layer的中图形缓冲区域对应的生产者// 创建native层的SurfacemSurfaceData = new Surface(mGraphicBufferProducer, false);return mSurfaceData;
}

至此,ViewRootImpl内持有的Suface就转变为可用状态,并指向正确的native层Surface对象引用,进而关联到SurfaceFlinger创建的BufferQueue

最后来简要概括一下Surface创建的过程

  • 首先由ViewRootImpl.requestLayout通过Choreographer向native申请Vsync同步信号。

  • App进程的Choreographer接收到Vsync同步信号后,通过SurfaceControl内部创建并持有对应的native层SurfaceControl对象引用地址。

  • 在native层 中用SurfaceSession中持有的SurfaceComposerClient通过Binder跨进程调用,在SurfaceFlinger进程内中创建一个独立的,基于BufferQueue的生产者消费者模型。

    在native层SurfaceControl创建时,会将BufferQueue的生产者Producer的Binder代理类对象赋值给其内部变量。

  • 由java层Surface.copyFrom藉由native层SurfaceControl创建native层的Surface对象,后者持有来自native层SurfaceControlProducer的对象引用。

    native层SurfaceControl内部会缓存native层Surface到内部变量引用,只会在第一次获取时创建。

    将该native层Surface对象引用地址赋值给jave层的Surface对象,使后者指向正确对象引用地址。

    java层的SurfaceSurfaceControl都是空壳,实际做事的都是native层的SurfaceSurfaceControl


http://www.ppmy.cn/news/522301.html

相关文章

Windows 8 Pro版Surface售价曝光

就在前不久微软Surface平板与Windows 8系统同步上市&#xff0c;其中不含键盘保护套的32GB版本售价3688元&#xff0c;附带黑色触控式键盘保护套的32GB版本售价4488元&#xff0c;附带黑色触控式键盘保护套的64GB版本售价5288元。 不过&#xff0c;相信更多的用户在等待微软的W…

别了微软Surface

不久前微软Surface RT平板电脑的发布被业内和微软寄予厚望&#xff0c;尤其微软曾预计到今年年底前将出货400万部Surface RT。不过近日来供应链消息称&#xff0c;微软的Surface RT平板电脑订单数量已经减少了近一半&#xff0c;与此同时&#xff0c;其它采用Windows RT设备的订…

surface

Surface是 美国 微软 公司 推出的全新 硬件 品牌&#xff0c; 微软 公司于2012年6月19日发布了Surface系列 平板电脑 。这款平板 电脑 采用镁合金机身10.6 英寸 显示屏&#xff0c; 配备 USB 2.0或3.0接口&#xff0c;使用 Windows 8操作系统。微软官网将其称…

Surface 和 SurfaceHolder

Surface 对象使应用能够渲染要在屏幕上显示的图像。通过 SurfaceHolder 接口&#xff0c;应用可以编辑和控制 Surface。 Surface Surface 是一个接口&#xff0c;供生产方与消耗方交换缓冲区。 用于显示 Surface 的 BufferQueue 通常配置为三重缓冲。缓冲区是按需分配的&…

Surface系统概述

一、前言 ​ 对于应用开发者来说&#xff0c;Android的界面以及各种UI元素都是通过View以及系统组件来显示的&#xff0c;那么在系统层面&#xff0c;我们写的View是怎么绘制到显示屏幕上的呢&#xff1f; ​ 我们知道SurfaceView是一种比较特殊的View&#xff0c;它包含有自…

windows 8 Surface 会成功吗?

Surface 会成功吗&#xff1f; Windows RT 的目标是在平板领域上挑战苹果 iOS 系统&#xff0c;但就目前来看还缺乏俘获消费者芳心的杀手级应用&#xff0c;无论时游戏还是办公应用都没有几个应用可以真正让消费者眼前一亮。 至于售价呢&#xff0c;美国价格为 32GB 的 Surface…

Microsoft Surface

Microsoft Surface&#xff0c;微软的第一款平面电脑&#xff0c;没有鼠标键盘&#xff0c;通过触摸等方式来进行交互&#xff0c;走入一种新的人和信息之间的交互方式。 具体了解可以看一下这篇文章: http://www.hi-id.com/?p1165 Surface视频展示&#xff1a; http://www.p…

Surface 之父 Panos Panay 加入微软高级领导层,Windows 重整旗鼓!

众所周知&#xff0c;微软起家靠的是 Windows 的崛起。在 Windows 的逐代更新中&#xff0c;微软也将其生态从操作系统拓展到软件、硬件、云计算、人工智能等多个领域&#xff0c;然而当围绕数字化为核心的第四次工业革命正式打响之际&#xff0c;微软为加快自身数字化转型的步…