yashsingh1/xdaforums huggingface dataset:
[Android Software/Hacking General [Developers Only]] llrraa2010:
Step 11. PackageParser.parseApplication

frameworks/base/core/java/android/content/pm/PackageParser.java

public class PackageParser {
......

private boolean parseApplication(Package owner, Resources res,
XmlPullParser parser, AttributeSet attrs, int flags, String[] outError)
throws XmlPullParserException, IOException {
final ApplicationInfo ai = owner.applicationInfo;
final String pkgName = owner.applicationInfo.packageName;

TypedArray sa = res.obtainAttributes(attrs,
com.android.internal.R.styleable.AndroidManifestApplication);

......

int type;
while ((type=parser.next()) != parser.END_DOCUMENT
&& (type != parser.END_TAG || parser.getDepth() > innerDepth)) {
if (type == parser.END_TAG || type == parser.TEXT) {
continue;
}

String tagName = parser.getName();
if (tagName.equals("activity")) {
Activity a = parseActivity(owner, res, parser, attrs, flags, outError, false);
......

owner.activities.add(a);

} else if (tagName.equals("receiver")) {
Activity a = parseActivity(owner, res, parser, attrs, flags, outError, true);
......

owner.receivers.add(a);
} else if (tagName.equals("service")) {
Service s = parseService(owner, res, parser, attrs, flags, outError);
......

owner.services.add(s);
} else if (tagName.equals("provider")) {
Provider p = parseProvider(owner, res, parser, attrs, flags, outError);
......

owner.providers.add(p);
} else if (tagName.equals("activity-alias")) {
Activity a = parseActivityAlias(owner, res, parser, attrs, flags, outError);
......

owner.activities.add(a);
} else if (parser.getName().equals("meta-data")) {
......
} else if (tagName.equals("uses-library")) {
......
} else if (tagName.equals("uses-package")) {
......
} else {
......
}
}

return true;
}

......
}
[Android Software/Hacking General [Developers Only]] llrraa2010:
Step 12. PackageManagerService.scanPackageLI

frameworks/base/services/java/com/android/server/PackageManagerService.java

class PackageManagerService extends IPackageManager.Stub {
......

// Keys are String (package name), values are Package. This also serves
// as the lock for the global state. Methods that must be called with
// this lock held have the prefix "LP".
final HashMap<String, PackageParser.Package> mPackages =
new HashMap<String, PackageParser.Package>();

......

// All available activities, for your resolving pleasure.
final ActivityIntentResolver mActivities =
new ActivityIntentResolver();

// All available receivers, for your resolving pleasure.
final ActivityIntentResolver mReceivers =
new ActivityIntentResolver();

// All available services, for your resolving pleasure.
final ServiceIntentResolver mServices = new ServiceIntentResolver();

// Keys are String (provider class name), values are Provider.
final HashMap<ComponentName, PackageParser.Provider> mProvidersByComponent =
new HashMap<ComponentName, PackageParser.Provider>();

......

private PackageParser.Package scanPackageLI(PackageParser.Package pkg,
int parseFlags, int scanMode, long currentTime) {
......

synchronized (mPackages) {
......

// Add the new setting to mPackages
mPackages.put(pkg.applicationInfo.packageName, pkg);

......

int N = pkg.providers.size();
int i;
for (i=0; i<N; i++) {
PackageParser.Provider p = pkg.providers.get(i);
p.info.processName = fixProcessName(pkg.applicationInfo.processName,
p.info.processName, pkg.applicationInfo.uid);
mProvidersByComponent.put(new ComponentName(p.info.packageName,
p.info.name), p);

......
}

N = pkg.services.size();
for (i=0; i<N; i++) {
PackageParser.Service s = pkg.services.get(i);
s.info.processName = fixProcessName(pkg.applicationInfo.processName,
s.info.processName, pkg.applicationInfo.uid);
mServices.addService(s);

......
}

N = pkg.receivers.size();
r = null;
for (i=0; i<N; i++) {
PackageParser.Activity a = pkg.receivers.get(i);
a.info.processName = fixProcessName(pkg.applicationInfo.processName,
a.info.processName, pkg.applicationInfo.uid);
mReceivers.addActivity(a, "receiver");

......
}

N = pkg.activities.size();
for (i=0; i<N; i++) {
PackageParser.Activity a = pkg.activities.get(i);
a.info.processName = fixProcessName(pkg.applicationInfo.processName,
a.info.processName, pkg.applicationInfo.uid);
mActivities.addActivity(a, "activity");

......
}

......
}

......

return pkg;
}

......
}
[Android Software/Hacking General [Developers Only]] llrraa2010:
11.2　start of Zygote
[Android Software/Hacking General [Developers Only]] llrraa2010:
Step 1. app_process.main

frameworks/base/cmds/app_process/app_main.cpp

int main(int argc, const char* const argv[])
{
// These are global variables in ProcessState.cpp
mArgC = argc;
mArgV = argv;

mArgLen = 0;
for (int i=0; i<argc; i++) {
mArgLen += strlen(argv[i]) + 1;
}
mArgLen--;

AppRuntime runtime;
const char *arg;
argv0 = argv[0];

// Process command line arguments
// ignore argv[0]
argc--;
argv++;

// Everything up to '--' or first non '-' arg goes to the vm

int i = runtime.addVmArguments(argc, argv);

// Next arg is parent directory
if (i < argc) {
runtime.mParentDir = argv[i++];
}

// Next arg is startup classname or "--zygote"
if (i < argc) {
arg = argv[i++];
if (0 == strcmp("--zygote", arg)) {
bool startSystemServer = (i < argc) ?
strcmp(argv[i], "--start-system-server") == 0 : false;
setArgv0(argv0, "zygote");
set_process_name("zygote");
runtime.start("com.android.internal.os.ZygoteInit",
startSystemServer);
} else {
set_process_name(argv0);

runtime.mClassName = arg;

// Remainder of args get passed to startup class main()
runtime.mArgC = argc-i;
runtime.mArgV = argv+i;

LOGV("App process is starting with pid=%d, class=%s.\n",
getpid(), runtime.getClassName());
runtime.start();
}
} else {
LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
fprintf(stderr, "Error: no class name or --zygote supplied.\n");
app_usage();
return 10;
}

}
[Android Software/Hacking General [Developers Only]] llrraa2010:
Step 2. AndroidRuntime.start

frameworks/base/core/jni/AndroidRuntime.cpp

/*
* Start the Android runtime. This involves starting the virtual machine
* and calling the "static void main(String[] args)" method in the class
* named by "className".
*/
void AndroidRuntime::start(const char* className, const bool startSystemServer)
{
......

char* slashClassName = NULL;
char* cp;
JNIEnv* env;

......

/* start the virtual machine */
if (startVm(&mJavaVM, &env) != 0)
goto bail;

/*
* Register android functions.
*/
if (startReg(env) < 0) {
LOGE("Unable to register all android natives\n");
goto bail;
}

/*
* We want to call main() with a String array with arguments in it.
* At present we only have one argument, the class name. Create an
* array to hold it.
*/
jclass stringClass;
jobjectArray strArray;
jstring classNameStr;
jstring startSystemServerStr;
stringClass = env->FindClass("java/lang/String");
assert(stringClass != NULL);
strArray = env->NewObjectArray(2, stringClass, NULL);
assert(strArray != NULL);
classNameStr = env->NewStringUTF(className);
assert(classNameStr != NULL);
env->SetObjectArrayElement(strArray, 0, classNameStr);
startSystemServerStr = env->NewStringUTF(startSystemServer ?
"true" : "false");
env->SetObjectArrayElement(strArray, 1, startSystemServerStr);

/*
* Start VM. This thread becomes the main thread of the VM, and will
* not return until the VM exits.
*/
jclass startClass;
jmethodID startMeth;

slashClassName = strdup(className);
for (cp = slashClassName; *cp != '\0'; cp++)
if (*cp == '.')
*cp = '/';

startClass = env->FindClass(slashClassName);
if (startClass == NULL) {
......
} else {
startMeth = env->GetStaticMethodID(startClass, "main",
"([Ljava/lang/String;)V");
if (startMeth == NULL) {
......
} else {
env->CallStaticVoidMethod(startClass, startMeth, strArray);
......
}
}

......
}
[Android Software/Hacking General [Developers Only]] llrraa2010:
Step 3. ZygoteInit.main

frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

public class ZygoteInit {
......

public static void main(String argv[]) {
try {
......

registerZygoteSocket();

......

......

if (argv[1].equals("true")) {
startSystemServer();
} else if (!argv[1].equals("false")) {
......
}

......

if (ZYGOTE_FORK_MODE) {
......
} else {
runSelectLoopMode();
}

......
} catch (MethodAndArgsCaller caller) {
......
} catch (RuntimeException ex) {
......
}
}

......
}
[Android Software/Hacking General [Developers Only]] llrraa2010:
Step 4. ZygoteInit.registerZygoteSocket

frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

public class ZygoteInit {
......

/**
* Registers a server socket for zygote command connections
*
* @throws RuntimeException when open fails
*/
private static void registerZygoteSocket() {
if (sServerSocket == null) {
int fileDesc;
try {
String env = System.getenv(ANDROID_SOCKET_ENV);
fileDesc = Integer.parseInt(env);
} catch (RuntimeException ex) {
......
}

try {
sServerSocket = new LocalServerSocket(
createFileDescriptor(fileDesc));
} catch (IOException ex) {
.......
}
}
}

......
}
[Android Software/Hacking General [Developers Only]] llrraa2010:
Step 5. ZygoteInit.startSystemServer

frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

public class ZygoteInit {
......

private static boolean startSystemServer()
throws MethodAndArgsCaller, RuntimeException {
/* Hardcoded command line to start the system server */
String args[] = {
"--setuid=1000",
"--setgid=1000",
"--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,3001,3002,3003",
"--capabilities=130104352,130104352",
"--runtime-init",
"--nice-name=system_server",
"com.android.server.SystemServer",
};
ZygoteConnection.Arguments parsedArgs = null;

int pid;

try {
parsedArgs = new ZygoteConnection.Arguments(args);

......

/* Request to fork the system server process */
pid = Zygote.forkSystemServer(
parsedArgs.uid, parsedArgs.gid,
parsedArgs.gids, debugFlags, null,
parsedArgs.permittedCapabilities,
parsedArgs.effectiveCapabilities);
} catch (IllegalArgumentException ex) {
......
}

/* For child process */
if (pid == 0) {
handleSystemServerProcess(parsedArgs);
}

return true;
}

......
}
[Android Software/Hacking General [Developers Only]] llrraa2010:
Step 6. ZygoteInit.handleSystemServerProcess

frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

public class ZygoteInit {
......

private static void handleSystemServerProcess(
ZygoteConnection.Arguments parsedArgs)
throws ZygoteInit.MethodAndArgsCaller {
closeServerSocket();

/*
* Pass the remaining arguments to SystemServer.
* "--nice-name=system_server com.android.server.SystemServer"
*/
RuntimeInit.zygoteInit(parsedArgs.remainingArgs);
/* should never reach here */
}

......
}
[Android Software/Hacking General [Developers Only]] llrraa2010:
Step 7. RuntimeInit.zygoteInit

frameworks/base/core/java/com/android/internal/os/RuntimeInit.java

public class RuntimeInit {
......

public static final void zygoteInit(String[] argv)
throws ZygoteInit.MethodAndArgsCaller {
......

zygoteInitNative();

......

// Remaining arguments are passed to the start class's static main

String startClass = argv[curArg++];
String[] startArgs = new String[argv.length - curArg];

System.arraycopy(argv, curArg, startArgs, 0, startArgs.length);
invokeStaticMain(startClass, startArgs);
}

......
}
[Android Software/Hacking General [Developers Only]] llrraa2010:
Step 8. RuntimeInit.zygoteInitNative

frameworks/base/core/java/com/android/internal/os/RuntimeInit.java

public class RuntimeInit {

......

public static final native void zygoteInitNative();

......

}
[Android Software/Hacking General [Developers Only]] llrraa2010:
Step 9. SystemServer.main

frameworks/base/services/java/com/android/server/SystemServer.java

public class SystemServer
{
......

native public static void init1(String[] args);

......

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

init1(args);

......
}

public static final void init2() {
Slog.i(TAG, "Entered the Android system server!");
Thread thr = new ServerThread();
thr.setName("android.server.ServerThread");
thr.start();
}

......
}
[Android Software/Hacking General [Developers Only]] llrraa2010:
Step 10. ZygoteInit.runSelectLoopMode

frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

public class ZygoteInit {
......

private static void runSelectLoopMode() throws MethodAndArgsCaller {
ArrayList<FileDescriptor> fds = new ArrayList();
ArrayList<ZygoteConnection> peers = new ArrayList();
FileDescriptor[] fdArray = new FileDescriptor[4];

fds.add(sServerSocket.getFileDescriptor());
peers.add(null);

int loopCount = GC_LOOP_COUNT;
while (true) {
int index;

......

try {
fdArray = fds.toArray(fdArray);
index = selectReadable(fdArray);
} catch (IOException ex) {
throw new RuntimeException("Error in select()", ex);
}

if (index < 0) {
throw new RuntimeException("Error in select()");
} else if (index == 0) {
ZygoteConnection newPeer = acceptCommandPeer();
peers.add(newPeer);
fds.add(newPeer.getFileDesciptor());
} else {
boolean done;
done = peers.get(index).runOnce();

if (done) {
peers.remove(index);
fds.remove(index);
}
}
}
}

......
}
[Android Software/Hacking General [Developers Only]] llrraa2010:
chapter 3 smart pointer

3.1　light weight pointer

3.1.1　implementation

frameworks/base/include/utils/RefBase.h

template <class T>
class LightRefBase
{
public:
inline LightRefBase() : mCount(0) { }
inline void incStrong(const void* id) const {
android_atomic_inc(&mCount);
}
inline void decStrong(const void* id) const {
if (android_atomic_dec(&mCount) == 1) {
delete static_cast<const T*>(this);
}
}
//! DEBUGGING ONLY: Get current strong ref count.
inline int32_t getStrongCount() const {
return mCount;
}

protected:
inline ~LightRefBase() { }

private:
mutable volatile int32_t mCount;
};
[Android Software/Hacking General [Developers Only]] llrraa2010:
frameworks/base/include/utils/RefBase.h

template <typename T>
class sp
{
public:
typedef typename RefBase::weakref_type weakref_type;

inline sp() : m_ptr(0) { }

sp(T* other);
sp(const sp<T>& other);
template<typename U> sp(U* other);
template<typename U> sp(const sp<U>& other);

~sp();

// Assignment

sp& operator = (T* other);
sp& operator = (const sp<T>& other);

template<typename U> sp& operator = (const sp<U>& other);
template<typename U> sp& operator = (U* other);

//! Special optimization for use by ProcessState (and nobody else).
void force_set(T* other);

// Reset

void clear();

// Accessors

inline T& operator* () const { return *m_ptr; }
inline T* operator-> () const { return m_ptr; }
inline T* get() const { return m_ptr; }

// Operators

COMPARE(==)
COMPARE(!=)
COMPARE(>)
COMPARE(<)
COMPARE(<=)
COMPARE(>=)

private:
template<typename Y> friend class sp;
template<typename Y> friend class wp;

// Optimization for wp::promote().
sp(T* p, weakref_type* refs);

T* m_ptr;
};
[Android Software/Hacking General [Developers Only]] llrraa2010:
3.1.2　example

External/lightpointer/lightpointer.cpp

#include <stdio.h>
#include <utils/RefBase.h>

using namespace android;

class LightClass : public LightRefBase<LightClass>
{
public:
LightClass()
{
printf("Construct LightClass Object.");
}

virtual ~LightClass()
{
printf("Destory LightClass Object.");
}
};

int main(int argc, char** argv)
{
LightClass* pLightClass = new LightClass();
sp<LightClass> lpOut = pLightClass;

printf("Light Ref Count: %d.\n", pLightClass->getStrongCount());

{
sp<LightClass> lpInner = lpOut;

printf("Light Ref Count: %d.\n", pLightClass->getStrongCount());
}

printf("Light Ref Count: %d.\n", pLightClass->getStrongCount());

return 0;
}
[Android Software/Hacking General [Developers Only]] llrraa2010:
External/lightpointer/Android.mk

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE := lightpointer
LOCAL_SRC_FILES := lightpointer.cpp
LOCAL_SHARED_LIBRARIES := \
libcutils \
libutils
include $(BUILD_EXECUTABLE)
[Android Software/Hacking General [Developers Only]] llrraa2010:
build:

USER-NAME@MACHINE-NAME:~/Android$ mmm ./external/lightpointer

pack:

USER-NAME@MACHINE-NAME:~/Android$ make snod

run:

USER-NAME@MACHINE-NAME:~/Android$ adb shell
root@android:/ # cd system/bin/
root@android:/system/bin # ./lightpointer
Construct LightClass Object.
Light Ref Count: 1.
Light Ref Count: 2.
Light Ref Count: 1.
Destory LightClass Object.
[Android Software/Hacking General [Developers Only]] llrraa2010:
frameworks/base/include/utils/RefBase.h

class RefBase
{
public:
void incStrong(const void* id) const;
void decStrong(const void* id) const;

void forceIncStrong(const void* id) const;

//! DEBUGGING ONLY: Get current strong ref count.
int32_t getStrongCount() const;

class weakref_type
{
public:
RefBase* refBase() const;

void incWeak(const void* id);
void decWeak(const void* id);

bool attemptIncStrong(const void* id);

//! This is only safe if you have set OBJECT_LIFETIME_FOREVER.
bool attemptIncWeak(const void* id);

//! DEBUGGING ONLY: Get current weak ref count.
int32_t getWeakCount() const;

//! DEBUGGING ONLY: Print references held on object.
void printRefs() const;

//! DEBUGGING ONLY: Enable tracking for this object.
// enable -- enable/disable tracking
// retain -- when tracking is enable, if true, then we save a stack trace
// for each reference and dereference; when retain == false, we
// match up references and dereferences and keep only the
// outstanding ones.

void trackMe(bool enable, bool retain);
};

weakref_type* createWeak(const void* id) const;

weakref_type* getWeakRefs() const;

//! DEBUGGING ONLY: Print references held on object.
inline void printRefs() const { getWeakRefs()->printRefs(); }

//! DEBUGGING ONLY: Enable tracking of object.
inline void trackMe(bool enable, bool retain)
{
getWeakRefs()->trackMe(enable, retain);
}

protected:
RefBase();
virtual ~RefBase();

//! Flags for extendObjectLifetime()
enum {
OBJECT_LIFETIME_WEAK = 0x0001,
OBJECT_LIFETIME_FOREVER = 0x0003
};

void extendObjectLifetime(int32_t mode);

//! Flags for onIncStrongAttempted()
enum {
FIRST_INC_STRONG = 0x0001
};

virtual void onFirstRef();
virtual void onLastStrongRef(const void* id);
virtual bool onIncStrongAttempted(uint32_t flags, const void* id);
virtual void onLastWeakRef(const void* id);

private:
friend class weakref_type;
class weakref_impl;

RefBase(const RefBase& o);
RefBase& operator=(const RefBase& o);

weakref_impl* const mRefs;
};
[Android Software/Hacking General [Developers Only]] llrraa2010:
frameworks/base/libs/utils/RefBase.cpp

class RefBase::weakref_impl : public RefBase::weakref_type
{
public:
volatile int32_t mStrong;
volatile int32_t mWeak;
RefBase* const mBase;
volatile int32_t mFlags;

#if !DEBUG_REFS

weakref_impl(RefBase* base)
: mStrong(INITIAL_STRONG_VALUE)
, mWeak(0)
, mBase(base)
, mFlags(0)
{
}

void addStrongRef(const void* /*id*/) { }
void removeStrongRef(const void* /*id*/) { }
void addWeakRef(const void* /*id*/) { }
void removeWeakRef(const void* /*id*/) { }
void printRefs() const { }
void trackMe(bool, bool) { }

#else
weakref_impl(RefBase* base)
: mStrong(INITIAL_STRONG_VALUE)
, mWeak(0)
, mBase(base)
, mFlags(0)
, mStrongRefs(NULL)
, mWeakRefs(NULL)
, mTrackEnabled(!!DEBUG_REFS_ENABLED_BY_DEFAULT)
, mRetain(false)
{
//LOGI("NEW weakref_impl %p for RefBase %p", this, base);
}

~weakref_impl()
{
LOG_ALWAYS_FATAL_IF(!mRetain && mStrongRefs != NULL, "Strong references remain!");
LOG_ALWAYS_FATAL_IF(!mRetain && mWeakRefs != NULL, "Weak references remain!");
}

void addStrongRef(const void* id)
{
addRef(&mStrongRefs, id, mStrong);
}

void removeStrongRef(const void* id)
{
if (!mRetain)
removeRef(&mStrongRefs, id);
else
addRef(&mStrongRefs, id, -mStrong);
}

void addWeakRef(const void* id)
{
addRef(&mWeakRefs, id, mWeak);
}
void removeWeakRef(const void* id)
{
if (!mRetain)
removeRef(&mWeakRefs, id);
else
addRef(&mWeakRefs, id, -mWeak);
}

void trackMe(bool track, bool retain)
{
mTrackEnabled = track;
mRetain = retain;
}

......

private:
struct ref_entry
{
ref_entry* next;
const void* id;
#if DEBUG_REFS_CALLSTACK_ENABLED
CallStack stack;
#endif
int32_t ref;
};

void addRef(ref_entry** refs, const void* id, int32_t mRef)
{
if (mTrackEnabled) {
AutoMutex _l(mMutex);
ref_entry* ref = new ref_entry;
// Reference count at the time of the snapshot, but before the
// update. Positive value means we increment, negative--we
// decrement the reference count.
ref->ref = mRef;
ref->id = id;
#if DEBUG_REFS_CALLSTACK_ENABLED
ref->stack.update(2);
#endif

ref->next = *refs;
*refs = ref;
}
}

void removeRef(ref_entry** refs, const void* id)
{
if (mTrackEnabled) {
AutoMutex _l(mMutex);

ref_entry* ref = *refs;
while (ref != NULL) {
if (ref->id == id) {
*refs = ref->next;
delete ref;
return;
}

refs = &ref->next;
ref = *refs;
}

LOG_ALWAYS_FATAL("RefBase: removing id %p on RefBase %p (weakref_type %p) that doesn't exist!",
id, mBase, this);
}
}

......

Mutex mMutex;
ref_entry* mStrongRefs;
ref_entry* mWeakRefs;

bool mTrackEnabled;
// Collect stack traces on addref and removeref, instead of deleting the stack references
// on removeref that match the address ones.
bool mRetain;

......
#endif
};
[Android Software/Hacking General [Developers Only]] llrraa2010:
[IMG="RefBase class diagram"]http://hi.csdn.net/attachment/201109/22/0_1316705573tFI6.gif[/IMG]
[Android Software/Hacking General [Developers Only]] llrraa2010:
frameworks/base/libs/utils/RefBase.cpp

void RefBase::incStrong(const void* id) const
{
weakref_impl* const refs = mRefs;
refs->addWeakRef(id);
refs->incWeak(id);
refs->addStrongRef(id);

const int32_t c = android_atomic_inc(&refs->mStrong);
LOG_ASSERT(c > 0, "incStrong() called on %p after last strong ref", refs);

#if PRINT_REFS
LOGD("incStrong of %p from %p: cnt=%d\n", this, id, c);
#endif

if (c != INITIAL_STRONG_VALUE) {
return;
}

android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong);
const_cast<RefBase*>(this)->onFirstRef();
}
[Android Software/Hacking General [Developers Only]] llrraa2010:
frameworks/base/libs/utils/RefBase.cpp
void RefBase::decStrong(const void* id) const
{
weakref_impl* const refs = mRefs;
refs->removeStrongRef(id);
const int32_t c = android_atomic_dec(&refs->mStrong);
#if PRINT_REFS
LOGD("decStrong of %p from %p: cnt=%d\n", this, id, c);
#endif
LOG_ASSERT(c >= 1, "decStrong() called on %p too many times", refs);
if (c == 1) {
const_cast<RefBase*>(this)->onLastStrongRef(id);
if ((refs->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) {
delete this;
}
}
refs->removeWeakRef(id);
refs->decWeak(id);
}