Android源码中有大量的智能指针,它们经常使用,通常一个类前会修饰sp或者wp,这种修饰即为智能指针。

Android智能指针解析

1简介

智能指针C++11就存在,是为了媲美javaJVM,完全不用管对象的回收问题。

Android的智能指针,巧妙的运用C++的基础特性,实现对象的自动释放。

2智能指针原理

2.1作用域

2.1.1栈空间

 1//demo1
 2class Yangyang
 3{};
 4//yangyang1的作用域开始
 5void demo1()
 6{
 7    Yangyang yangyang1;
 8    //yangyang2的作用域开始
 9    {
10        Yangyang yangyang2;
11    }
12    //yangyang2的作用域结束
13}
14//yangyang1的作用域结束

可以看出局部变量的作用域实际上是最近一对括号包含的范围。

2.1.2堆空间

 1//demo2
 2class Yangyang
 3{};
 4
 5void demo2()
 6{
 7    Yangyang stackYangyang;
 8    //pHeapYangyang是栈空间的变量,但是指向的是堆空间变量
 9    Yangyang* pHeapYangyang = new Yangyang;
10    //指向堆空间变量的栈变量需要手动释放
11    delete pHeapYangyang;
12    //将指向堆空间的栈变量指向nullptr,防止造成野指针
13    pHeapYangyang = nullptr;
14}

3源码解析

源码里主要用到了sp(强引用指针)和wp(弱引用指针)的智能指针,当然还有其他类似LightRefBase(本文不做介绍)。

Android设计了强引用sp和弱引用wp,故实际对象的释放,可分为强引用控制和弱引用控制。前者是,指的是强引用数mStrong为0时,释放实际对象;后者是,则指的是弱引用数mWeak为0时,才释放实际对象。

3.1举例说明

 1//demo3
 2class Yangyang : public RefBase
 3{
 4    Yangyang() : RefBase()
 5    {
 6        //可以显示调用RefBase构造
 7        cout << "Yangyang Constructor" << endl;
 8    }
 9    virtual ~Yangyang()
10    {
11        //声明virtual,可以从Yangyang派生
12        cout << "Yangyang Destructor" << endl;
13    }
14};
15
16void demo3()
17{
18    //new一个对象,pYangyang指向的是一个堆空间
19    Yangyang* pYangyang = new Yangyang();
20    //限定sp的作用域,利用sp的栈变量,spYangyang
21    {
22        sp<Yangyang> spYangyang(pYangyang);
23        //限定wp的作用域,利用wp的栈变量,wpYangyang
24        {
25            wp<Yangyang> wpYangyang(pYangyang);
26        }
27        //wpYangyang作用域结束
28    }
29    //spYangyang作用域结束
30}

结果显示

 1Yangyang::-----demo3--
 2Yangyang::Yangyang Constructor this(0x21127080)
 3Yangyang:No refs,strong count(0x10000000),weak count(0)
 4Yangyang:in sp scope Yangyang:onFirstRef,object(0x21127080)
 5Yangyang::After strong ref,strong count(1), weak count(1)
 6Yangyang:in wp scope Yangyang::After weak ref,strong count(1),weak count(2)
 7Yangyang:out wp scope Yangyang:release weak ref,strong count(1),weak count(1)
 8Yangyang::out sp scope Yangyang:onLastStrongRef,id(0x21712848)
 9Yangyang:Yangyang Destructor  this(0x21127080)
10Yangyang::------

3.2RefBase

RefBase构造

 1//system/core/libutils/RefBase.cpp
 2//INITIAL_STRONG_VALUE 0x10000000
 3//这个传入的base就是实际对象pYangyang
 4//mFlags表示是否强引用,0是强引用,1是弱引用
 5explicit weakref_impl(RefBase* base)
 6: mStrong(INITIAL_STRONG_VALUE)
 7    , mWeak(0)
 8    , mBase(base)
 9    , mFlags(0)
10{
11}
12
13//这里的this指的就是Yangyang的实例化对象pYangyang
14RefBase::RefBase()
15    : mRefs(new weakref_impl(this))
16{
17}

3.3sp构造

sp构造

 1//system/core/libutils/include/utils/StrongPointer.h
 2inline sp() : m_ptr(nullptr) { }
 3
 4//这里的T就是Yangyang类,other就是pYangyang
 5//这里的this,实际上是spYangyang栈变量的地址
 6template<typename T>
 7sp<T>::sp(T* other)
 8    : m_ptr(other) {
 9    if (other) {
10        check_not_on_stack(other);
11        other->incStrong(this);
12    }
13}

因为pYangyangYangyang类,继承RefBase,所以可以找到基类RefBase对应的函数incStrong

 1//system/core/libutils/RefBase.cpp
 2//这里的mRefs实际上是new weakref_impl(pYangyang)
 3void RefBase::incStrong(const void* id) const
 4{
 5    weakref_impl* const refs = mRefs;
 6    //1.弱引用增加1
 7    refs->incWeak(id);
 8    
 9    refs->addStrongRef(id);
10    //2-1.fetch_add操作之后,refs->mStrong=0x10000001,c=0x10000000
11    const int32_t c = refs->mStrong.fetch_add(1, std::memory_order_relaxed);
12    ...
13	//2-2.fetch_sub操作之后,refs->mStrong=1,c=0x10000001
14    int32_t old __unused = refs->mStrong.fetch_sub(INITIAL_STRONG_VALUE, std::memory_order_relaxed);
15
16    //3调用onFirstRef,实际上调用的是pYangyang->onFirstRef
17    refs->mBase->onFirstRef();
18}

这里存在一些原子操作的函数/system/core/libcutils/include/cutils/atomic.h

函数名 含义
android_atomic_inc 自增函数,返回值为旧值*ptr =*ptr + 1
android_atomic_dec 自减函数,返回值为旧值*ptr =*ptr - 1
android_atomic_add 加函数,返回值为旧值*ptr =*ptr + increment
android_atomic_and 位与函数,返回值为旧值*ptr =*ptr & value
android_atomic_or 位或函数,返回值为旧值`*ptr =*ptr
fetch_add 自增函数,返回值为旧值。*this =*this + 1
fetch_sub 自减函数,返回值为旧值。*this =*this - 1

incWeak

 1//system/core/libutils/RefBase.cpp
 2//这里的this指针是上面的mRefs,类型为weakref_impl* const
 3void RefBase::weakref_type::incWeak(const void* id)
 4{
 5    weakref_impl* const impl = static_cast<weakref_impl*>(this);
 6    impl->addWeakRef(id);
 7    //fetch_add之后,impl->mWeak=1,c=0
 8    const int32_t c __unused = impl->mWeak.fetch_add(1,
 9            std::memory_order_relaxed);
10    ALOG_ASSERT(c >= 0, "incWeak called on %p after last weak ref", this);
11}

因此,sp构造完成后,mRefs的弱引用数变为1,强引用数也变为1;第一次强引用时,回调onFirstRef()

3.4wp构造

弱引用构造

1//system/core/libutils/include/utils/RefBase.h
2//这里的T就是Yangyang类,other就是pYangyang
3//这里的this,实际上是wpYangyang栈变量的地址
4template<typename T>
5wp<T>::wp(T* other)
6    : m_ptr(other)
7{
8    m_refs = other ? m_refs = other->createWeak(this) : nullptr;
9}

这里的demo不存在会创建对象失败的情况,所以这里的wp中的m_refsother->createWeak(this),即pYangyang->createWeak(&wpYangyang)

1//system/core/libutils/RefBase.cpp
2//这里的返回值会返回当前的mRefs,是new weakref_impl(pYangyang)
3RefBase::weakref_type* RefBase::createWeak(const void* id) const
4{
5    //这里的mRefs就是new weakref_impl(pYangyang)
6    mRefs->incWeak(id);
7    return mRefs;
8}

incWeak在3.3中已经出现过了,作用是原子操作,让mRefs->mWeak增加1

调用incWeak,最终的影响是弱引用数+1。当前的demo3中,强引用数为1,弱引用数为2。

RefBase构造的时候,mFlags默认为0,即OBJECT_LIFETIME_STRONG,强引用控制。设置为OBJECT LIFETIME WEAK时,为弱引用控制。可以通过extendObjectLifetime函数修改

1//system/core/libutils/RefBase.cpp
2//如果仅仅是弱引用,需要mFlags修改成1
3void RefBase::extendObjectLifetime(int32_t mode)
4{
5    // Must be happens-before ordered with respect to construction or any
6    // operation that could destroy the object.
7    mRefs->mFlags.fetch_or(mode, std::memory_order_relaxed);
8}

3.5wp析构

wp作用域结束,弱引用开始析构

1//system/core/libutils/include/utils/RefBase.h
2//这里的m_ptr是pYangyang,因为还存在所以可以操作
3//这里的m_refs是new weakref_impl(pYangyang)
4//这里的this,实际上是wpYangyang栈变量的地址
5template<typename T>
6wp<T>::~wp()
7{
8    if (m_ptr) m_refs->decWeak(this);
9}

由于m_refs的变量是基类,m_refs所指向的指针是派生类,这里的decWeak不是virtual标识,只能调用基类的decWeak函数

 1//system/core/libutils/RefBase.cpp
 2void RefBase::weakref_type::decWeak(const void* id)
 3{
 4    //这里的static_cast就是子父类的向下转换
 5    weakref_impl* const impl = static_cast<weakref_impl*>(this);
 6    impl->removeWeakRef(id);
 7    //fetch_sub,mRefs->mWeak=0,c=1
 8    const int32_t c = impl->mWeak.fetch_sub(1, std::memory_order_release);
 9    //如果同时出现sp和wp的时候,mWeak的计数会是2,这里的c返回旧值也是2,直接返回
10    if (c != 1) return;
11    atomic_thread_fence(std::memory_order_acquire);
12
13    int32_t flags = impl->mFlags.load(std::memory_order_relaxed);
14    //如果是强引用
15    if ((flags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG) {
16        //如果强引用的mStrong元素时0x10000000,那么强引用错误
17        if (impl->mStrong.load(std::memory_order_relaxed)
18                == INITIAL_STRONG_VALUE) {
19            ALOGW("RefBase: Object at %p lost last weak reference "
20                    "before it had a strong reference", impl->mBase);
21        } else {
22            //如果强引用mStrong是其他值,释放impl,这里实际上释放的是mRefs
23            //这里不能直接释放pYangyang,可能计数还没完全减掉
24            delete impl;
25        }
26    } else {
27        //如果只是弱引用,调用onLastWeakRef,这个impl->mBase实际上是pYangyang,即pYangyang->onLastWeakRef
28        //然后把弱引用中的impl->mBase释放,即释放的是pYangyang,会调用pYangyang的析构函数
29        impl->mBase->onLastWeakRef(id);
30        delete impl->mBase;
31    }
32}

wp析构,情况比较复杂

  • 弱引用数减1
  • 最后一次弱引用时,如果是强引用控制,释放mRfs
  • 若没有强引用,释放实际对象pYangyang

demo3来看,此时,强引用数为1,弱引用数为1,并没有任何释放

3.6sp析构

sp作用域结束,强引用开始析构

1//system/core/libutils/include/utils/StrongPointer.h
2//针对sp析构,m_ptr实际上是pYangyang,所以调用的是pYangyang基类RefBase的decStrong函数
3template<typename T>
4sp<T>::~sp() {
5    if (m_ptr)
6        m_ptr->decStrong(this);
7}

decStrong

 1//system/core/libutils/RefBase.cpp
 2//这里的mRefs
 3void RefBase::decStrong(const void* id) const
 4{
 5    weakref_impl* const refs = mRefs;
 6    refs->removeStrongRef(id);
 7    //做减操作,mStrong=0,c=1
 8    const int32_t c = refs->mStrong.fetch_sub(1, std::memory_order_release);
 9
10    if (c == 1) {
11        std::atomic_thread_fence(std::memory_order_acquire);
12        //如果是强引用,调用onLastStrongRef,这个impl->mBase实际上是pYangyang,即pYangyang->onLastStrongRef
13        refs->mBase->onLastStrongRef(id);
14        int32_t flags = refs->mFlags.load(std::memory_order_relaxed);
15        //如果是强引用
16        if ((flags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG) {
17            //这里的this指的是m_ptr,指向的是pYangyang,释放pYangyang,并调用其析构
18            delete this;
19        }
20    }
21	//做减操作,mWeak=0,c=1
22    refs->decWeak(id);
23}

3.7RefBase析构

析构完实际对象pYangyang之后,基类也同步析构

 1//system/core/libutils/RefBase.cpp
 2RefBase::~RefBase()
 3{
 4    int32_t flags = mRefs->mFlags.load(std::memory_order_relaxed);
 5	//如果是弱引用
 6    if ((flags & OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_WEAK) {
 7        //弱引用计算为0,那么就把mRefs释放
 8        if (mRefs->mWeak.load(std::memory_order_relaxed) == 0) {
 9            delete mRefs;
10        }
11    } else if (mRefs->mStrong.load(std::memory_order_relaxed) == INITIAL_STRONG_VALUE) {
12        //如果mStrong是0x10000000,会有RefBase相关的堆栈
13        ALOGD("RefBase: Explicit destruction, weak count = %d (in %p)", mRefs->mWeak.load(), this);
14        CallStack::logStack(LOG_TAG);
15    }
16    //清除mRefs。对未完成的wp无效
17    const_cast<weakref_impl*&>(mRefs) = nullptr;
18}

3.8总结

1)仅有sp的时候(绿色是构造,红色是析构)

2)仅有wp的时候(绿色是构造,红色是析构)

3)有sp和wp的时候(绿色是构造,红色是析构)

  • 如果是demo3的场景,先出现析构wp,再出现析构sp场景

     1void demo3()
     2{
     3    //new一个对象,pYangyang指向的是一个堆空间
     4    Yangyang* pYangyang = new Yangyang();
     5    //限定sp的作用域,利用sp的栈变量,spYangyang
     6    {
     7        sp<Yangyang> spYangyang(pYangyang);
     8        //限定wp的作用域,利用wp的栈变量,wpYangyang
     9        {
    10            wp<Yangyang> wpYangyang(pYangyang);
    11        }
    12        //wpYangyang作用域结束
    13    }
    14    //spYangyang作用域结束
    15}
    
  • 如果是先析构sp,再出现析构wp的场景

     1void demo4()
     2{
     3    //new一个对象,pYangyang指向的是一个堆空间
     4    Yangyang* pYangyang = new Yangyang();
     5    //限wp的作用域,利用wp的栈变量,wpYangyang
     6    {
     7        wp<Yangyang> wpYangyang(pYangyang);
     8        //限定sp的作用域,利用sp的栈变量,spYangyang
     9        {
    10            sp<Yangyang> spYangyang(pYangyang);
    11        }
    12        //spYangyang作用域结束
    13    }
    14    //wpYangyang作用域结束
    15}
    

4智能指针使用

源码中大量使用spwp,而且用于很广泛,也无需考虑是否足要去释放

 1//frameworks/av/services/camera/libcameraservice/CameraService.cpp
 2void CameraService::updateProxyDeviceState(int newState,
 3        const String8& cameraId, int facing, const String16& clientName, int apiLevel) {
 4    sp<ICameraServiceProxy> proxyBinder = getCameraServiceProxy();
 5    if (proxyBinder == nullptr) return;
 6    String16 id(cameraId);
 7    proxyBinder->notifyCameraState(id, newState, facing, clientName, apiLevel);
 8}
 9
10sp<ICameraServiceProxy> CameraService::getCameraServiceProxy() {
11#ifndef __BRILLO__
12    Mutex::Autolock al(sProxyMutex);
13    if (sCameraServiceProxy == nullptr) {
14        //这里拿到ServiceManager的代理对象,即defaultServiceManager返回的是BpServiceManager
15        sp<IServiceManager> sm = defaultServiceManager();
16        //这里的checkService和getService类似,查找注册服务,前者是非阻塞,后者是阻塞的
17        sp<IBinder> binder = sm->checkService(String16("media.camera.proxy"));
18        if (binder != nullptr) {
19            //interface_cast会调用ICameraServiceProxy::asInterface(binder);
20            //asInterface又是在IInterface.h中定义的一个宏
21            //DO_NOT_DIRECTLY_USE_ME_IMPLEMENT_META_INTERFACE(INTERFACE, NAME)
22            sCameraServiceProxy = interface_cast<ICameraServiceProxy>(binder);
23        }
24    }
25#endif
26    return sCameraServiceProxy;
27}

上面以CameraService中的ICameraServiceProxy为例,这里的proxyBinder是一个栈变量,但是后面的proxyBinder->notifyCameraState,就直接将其当做一个指针使用。

这其实是正确的的,并不是乱写,一切都有迹可循

1)ICameraServiceProxy间接继承于RefBase,其中ICameraServiceProxy继承IInterfaceIInterface继承RefBase

 1//path:out/soong/.intermediates/frameworks/av/camera/libcamera_client/xxx/gen/aidl/android/hardware/
 2//file:ICameraServiceProxy.h
 3//file:BpCameraServiceProxy.h
 4//file:BnCameraServiceProxy.h
 5//其中这里是ICameraServiceProxy.h
 6//这里声明了一个宏,正好对应上面的ICameraServiceProxy::asInterface
 7//这个宏展开
 8/*
 9//这个传入的obj可知道是代理客户端的IBinder
10::android::sp<ICameraServiceProxy> ICameraServiceProxy::asInterface(
11        const ::android::sp<::android::IBinder>& obj)
12{
13    ::android::sp<ICameraServiceProxy> intr;
14    if (obj != nullptr) {
15        intr = static_cast<ICameraServiceProxy*>(
16        	//这里代理客户端的queryLocalInterface返回结果为nullptr
17            obj->queryLocalInterface(
18                    ICameraServiceProxy::descriptor).get());
19        if (intr == nullptr) {
20            intr = new BpCameraServiceProxy(obj);
21        }
22    }
23    return intr;
24}
25*/
26DO_NOT_DIRECTLY_USE_ME_IMPLEMENT_META_INTERFACE("CameraServiceProxy", "android.hardware.ICameraServiceProxy")
27class ICameraServiceProxy : public ::android::IInterface
28{...};

2)proxyBinder->notifyCameraState

1//system/core/libutils/include/utils/StrongPointer.h
2//proxyBinder->notifyCameraState转化为proxyBinder.operator->()->notifyCameraState,proxyBinder->()返回的是m_ptr,m_ptr指向ICameraServiceProxy的实例化对象,即ICameraServiceProxy的实例化对象的notifyCameraState调用
3inline T*       operator-> () const    { return m_ptr;  }

关于为什么关于'->‘运算符的重载会有.operator->()的解释,具体可以点击这里

这里就涉及到C++标准对->运算符的语义解释

因为运算符的结合律不同,解引用(*)是向右结合的,而 成员访问运算符(.->)是向左结合的。这是不同符号的结合律不同的例子,C++ 里符号相同的时候也会有用法不同导致结合律不同的例子。例如:

运算符 向左结合 向右结合
lhs op rhs / lhs op op rhs
++ -- 后缀递增/递减 前缀递增/递减
+ - 二进制加法/减法 一元加号/减号
* 二进制乘法 解引用
& 按位与 取地址
() 函数调用 类型转换

当你重载一个左结合律的操作符时(如+ - * / ()等),往往这个操作符是个二元操作符,对于lhs op rhs,就会调用lhs.operator op(rhs)operator op(lhs, rhs),我们只需要按照这个函数签名来重载操作符就行了。

但是,如果这个操作符是一元操作符怎么办?这就要分情况讨论了:

1)如果这个符号有一种以上的用法(比如++--),对于lhs op(左结合)和op rhs(右结合),我们得想个办法区分不同的用法啊,所以就会出现用于占位的函数参数(int):

  • 对于lhs op调用lhs.operator op(int)
  • 对于op rhs调用rhs.operator op()

2)如果这个符号只有一种用法(比如->),对于lhs op,那就不需要用于占位的函数参数了,可以直接写成类似右结合的函数签名,即

  • 对于lhs op调用lhs.operator op()

这是由 C++ 标准规定的,对于ptr->mem根据ptr类型的不同,操作符->的解释也不同:

  • ptr的类型是内置指针类型时,等价于(*ptr).mem
  • ptr的类型是类时,等价于ptr.operator->()->mem

你会发现这是一个递归的解释,对于ptr->mem会递归成:

1(*(ptr.operator->().operator->()..operator->())).mem

操作符->是一元的,而操作符.是二元的。操作符->最终是通过操作符.来访问成员的,而.这个操作符是不允许重载的,只能由编译器实现。

3)服务端实现,可以发现sp调用的客户端可以通过Binder调用到这里,即C++端为客户端,Java端为服务端

 1//frameworks/base/services/core/java/com/android/server/camera/CameraServiceProxy.java
 2//ICameraServiceProxy.Stub()这个是匿名内部类的方式继承来最终实现
 3private final ICameraServiceProxy.Stub mCameraServiceProxy = new ICameraServiceProxy.Stub() {
 4    @Override
 5    public void pingForUserUpdate() {
 6        if (Binder.getCallingUid() != Process.CAMERASERVER_UID) {
 7            Slog.e(TAG, "Calling UID: " + Binder.getCallingUid() + " doesn't match expected " +
 8                   " camera service UID!");
 9            return;
10        }
11        notifySwitchWithRetries(RETRY_TIMES);
12    }
13
14    @Override
15    public void notifyCameraState(String cameraId, int newCameraState, int facing,
16                                  String clientName, int apiLevel) {
17        if (Binder.getCallingUid() != Process.CAMERASERVER_UID) {
18            Slog.e(TAG, "Calling UID: " + Binder.getCallingUid() + " doesn't match expected " +
19                   " camera service UID!");
20            return;
21        }
22        String state = cameraStateToString(newCameraState);
23        String facingStr = cameraFacingToString(facing);
24        if (DEBUG) Slog.v(TAG, "Camera " + cameraId + " facing " + facingStr + " state now " +
25                          state + " for client " + clientName + " API Level " + apiLevel);
26
27        updateActivityCount(cameraId, newCameraState, facing, clientName, apiLevel);
28    }
29};

补充说明:C++端代理调用和Java端代理调用

  • Java端代理调用

    通过AIDL的方式,系统会生成一个ICameraServiceProxy.java文件,其中类图关系如下。

    调用方式

     1//1)调用asInterface
     2ICameraServiceProxy.Stub.asInterface(binder);
     3//2)判断是否是跨进程通信,如果不是返回null,如果是实例化一个代理类对象
     4mCameraServiceProxy = new ICameraServiceProxy.Stub.Proxy(binder);
     5//3)根据对象调用
     6mCameraServiceProxy.pingForUserUpdate();
     7//4)找到Proxy中的对应的方法,传递数据则用该方法中的transact
     8ICameraServiceProxy.Stub.Proxy.pingForUserUpdate#transact;
     9//5)找到Stub中的onTransact中的方法
    10ICameraServiceProxy.Stub.Proxy.pingForUserUpdate#onTransact;
    11//6)服务端实现ICameraServiceProxy.Stub接口,找到onTransact对应的pingForUserUpdate方法
    12new ICameraServiceProxy.Stub(){...@Override public void pingForUserUpdate() {} }
    
  • C++端代理调用

    通过AIDL的方式,系统会生成对应的四个文件,分别为ICameraServiceProxy.h,BpCameraServiceProxy.h,BnCameraServiceProxy.h,ICameraServiceProxy.cpp,具体的类图关系如下所示。

    调用方式

     1//1)defaultServiceManager返回一个BpServiceManager
     2sp<IServiceManager> sm = defaultServiceManager();
     3//2)找到对应service的IBinder,这里的IBinder是代理客户端的
     4sp<IBinder> binder = sm->checkService(String16("media.camera.proxy"));
     5//3)实例化一个代理类
     6//interface_cast<ICameraServiceProxy>(binder)转化为ICameraServiceProxy::asInterface(binder)
     7//asInterface调用到BpBinder中的queryLocalInterface,返回nullptr
     8///asInterface最后返回代理客户端的BpCameraServiceProxy实例化对象
     9sCameraServiceProxy = interface_cast<ICameraServiceProxy>(binder);
    10//4)根据对象调用
    11sCameraServiceProxy->pingForUserUpdate();
    12//5)调用到BpCameraServiceProxy.h中的函数,传递数据则用该方法中的transact
    13BpCameraServiceProxy::transact;
    14//6)BnCameraServiceProxy.h中的中的onTransact中的方法
    15BnCameraServiceProxy::onTransact;
    16//7)服务端找到onTransact中的pingForUserUpdate函数实现
    17BnCameraServiceProxy::pingForUserUpdate();
    

关于Binder流程中,defaultServiceManager返回的是BpServiceManager,可以点击这里,本文不过多介绍。

源码下载

sp_wp源码