diff --git a/mirai-api-http/src/main/kotlin/net.mamoe.mirai.api.http/MiraiHttpApplication.kt b/mirai-api-http/src/main/kotlin/net.mamoe.mirai.api.http/MiraiHttpApplication.kt
index 088725e25..c6bcf25c7 100644
--- a/mirai-api-http/src/main/kotlin/net.mamoe.mirai.api.http/MiraiHttpApplication.kt
+++ b/mirai-api-http/src/main/kotlin/net.mamoe.mirai.api.http/MiraiHttpApplication.kt
@@ -71,7 +71,7 @@ fun Application.mirai() {
     routing {
         mirai("/sendFriendMessage") {
             // TODO: 2019/11/21 解析图片消息等为 Message
-            Bot.instanceWhose(qq = param("bot")).getQQ(param("qq")).sendMessage(param<String>("message"))
+            Bot.instanceWhose(qq = param("bot")).getFriend(param("qq")).sendMessage(param<String>("message"))
             call.ok()
         }
 
diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/QQAndroidBot.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/QQAndroidBot.kt
index fc460a2ef..bbf097f45 100644
--- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/QQAndroidBot.kt
+++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/QQAndroidBot.kt
@@ -33,12 +33,8 @@ internal abstract class QQAndroidBotBase constructor(
 
     val selfQQ: QQ by lazy { QQ(uin) }
 
-    override fun getQQ(id: Long): QQ {
-        return qqs.delegate.filteringGetOrAdd({ it.id == id }, { QQImpl(this as QQAndroidBot, coroutineContext, id) })
-    }
-
-    fun getQQOrAdd(id: Long): QQ {
-        return qqs.delegate.filteringGetOrAdd({ it.id == id }, { QQImpl(this as QQAndroidBot, coroutineContext, id) })
+    override fun getFriend(id: Long): QQ {
+        return qqs.delegate[id]
     }
 
     override fun QQ(id: Long): QQ {
diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt
index 48d4cbffb..14b249287 100644
--- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt
+++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt
@@ -115,7 +115,8 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
 
         //val msg = MessageSvc.PbGetMsg(bot.client, MsgSvc.SyncFlag.START, currentTimeSeconds).sendAndExpect<MessageSvc.PbGetMsg.Response>()
         //println(msg.contentToString())
-
+        bot.qqs.delegate.clear()
+        bot.groups.delegate.clear()
 
         val startTime = currentTimeMillis
         try {
@@ -134,7 +135,7 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
                 totalFriendCount = data.totalFriendCount
                 data.friendList.forEach {
                     // atomic add
-                    bot.qqs.delegate.addLast(bot.getQQ(it.friendUin).also {
+                    bot.qqs.delegate.addLast(bot.getFriend(it.friendUin).also {
                         currentFriendCount++
                     })
                 }
@@ -475,12 +476,12 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
     /**
      * 发送一个包, 并挂起直到接收到指定的返回包或超时(3000ms)
      */
-    suspend fun <E : Packet> OutgoingPacket.sendAndExpect(timeoutMillis: Long = 3000, retry: Int = 1): E {
+    suspend fun <E : Packet> OutgoingPacket.sendAndExpect(timeoutMillis: Long = 3000, retry: Int = 0): E {
         require(timeoutMillis > 0) { "timeoutMillis must > 0" }
         require(retry >= 0) { "retry must >= 0" }
 
         var lastException: Exception? = null
-        repeat(retry + 1) {
+        if (retry == 0) {
             val handler = PacketListener(commandName = commandName, sequenceId = sequenceId)
             packetListeners.addLast(handler)
             try {
@@ -495,13 +496,33 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
                 } ?: net.mamoe.mirai.qqandroid.utils.inline {
                     error("timeout when receiving response of $commandName")
                 }
-            } catch (e: Exception) {
-                lastException = e
             } finally {
                 packetListeners.remove(handler)
             }
+        } else this.delegate.useBytes { data, length ->
+            repeat(retry + 1) {
+                val handler = PacketListener(commandName = commandName, sequenceId = sequenceId)
+                packetListeners.addLast(handler)
+                try {
+                    withContext(this@QQAndroidBotNetworkHandler.coroutineContext + CoroutineName("Packet sender")) {
+                        channel.send(data, 0, length)
+                    }
+                    bot.logger.info("Send: ${this.commandName}")
+                    return withTimeoutOrNull(timeoutMillis) {
+                        @Suppress("UNCHECKED_CAST")
+                        handler.await() as E
+                        // 不要 `withTimeout`. timeout 的异常会不知道去哪了.
+                    } ?: net.mamoe.mirai.qqandroid.utils.inline {
+                        error("timeout when receiving response of $commandName")
+                    }
+                } catch (e: Exception) {
+                    lastException = e
+                } finally {
+                    packetListeners.remove(handler)
+                }
+            }
+            throw lastException!!
         }
-        throw lastException!!
     }
 
     @PublishedApi
diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/MessageSvc.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/MessageSvc.kt
index 8c0ad5763..978af6ccd 100644
--- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/MessageSvc.kt
+++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/MessageSvc.kt
@@ -123,14 +123,11 @@ internal class MessageSvc {
 
             val messages = resp.uinPairMsgs.asSequence().filterNot { it.msg == null }.flatMap { it.msg!!.asSequence() }.mapNotNull {
                 when (it.msgHead.msgType) {
-                    166 -> {
-                        FriendMessage(
-                            bot,
-                            false, // TODO: 2020/1/29 PREVIOUS??
-                            bot.getQQ(it.msgHead.fromUin),
-                            it.msgBody.richText.toMessageChain()
-                        )
-                    }
+                    166 -> FriendMessage(
+                        bot,
+                        bot.getFriend(it.msgHead.fromUin),
+                        it.msgBody.richText.toMessageChain()
+                    )
                     else -> null
                 }
             }.toMutableList()
@@ -176,7 +173,7 @@ internal class MessageSvc {
             }
 
             data class Failed(val errorCode: Int, val errorMessage: String) : Response() {
-                override fun toString(): String = "MessageSvc.PbSendMsg.Response.FAILED(errorCode=$errorCode, errorMessage=$errorMessage"
+                override fun toString(): String = "MessageSvc.PbSendMsg.Response.Failed(errorCode=$errorCode, errorMessage=$errorMessage"
             }
         }
 
@@ -224,7 +221,7 @@ internal class MessageSvc {
             ///return@buildOutgoingUniPacket
             writeProtoBuf(
                 MsgSvc.PbSendMsgReq.serializer(), MsgSvc.PbSendMsgReq(
-                    routingHead = MsgSvc.RoutingHead(grp = MsgSvc.Grp(groupCode = groupCode)), // TODO: 2020/1/30 确认这里是 id 还是 internalId
+                    routingHead = MsgSvc.RoutingHead(grp = MsgSvc.Grp(groupCode = groupCode)),
                     contentHead = MsgComm.ContentHead(pkgNum = 1, divSeq = seq),
                     msgBody = ImMsgBody.MsgBody(
                         richText = ImMsgBody.RichText(
diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/Bot.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/Bot.kt
index 718a2ec10..f702bb57b 100644
--- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/Bot.kt
+++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/Bot.kt
@@ -58,9 +58,15 @@ abstract class Bot : CoroutineScope {
     abstract val qqs: ContactList<QQ>
 
     /**
-     * 获取一个好友对象. 若没有这个好友, 则会抛出异常[NoSuchElementException]
+     * 获取一个好友对象. 若没有这个好友, 则会抛出异常 [NoSuchElementException]
      */
-    abstract fun getQQ(id: Long): QQ
+    @Deprecated(message = "这个函数有歧义. 它获取的是好友, 却名为 getQQ", replaceWith = ReplaceWith("getFriend(id)"))
+    fun getQQ(id: Long): QQ = getFriend(id)
+
+    /**
+     * 获取一个好友对象. 若没有这个好友, 则会抛出异常 [NoSuchElementException]
+     */
+    abstract fun getFriend(id: Long): QQ
 
     /**
      * 构造一个 [QQ] 对象. 它持有对 [Bot] 的弱引用([WeakRef]).
@@ -133,8 +139,8 @@ abstract class Bot : CoroutineScope {
 
     // region extensions
 
-    fun Int.qq(): QQ = getQQ(this.toLong())
-    fun Long.qq(): QQ = getQQ(this)
+    fun Int.qq(): QQ = getFriend(this.toLong())
+    fun Long.qq(): QQ = getFriend(this)
 
 
     /**
diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/QQ.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/QQ.kt
index 289dcef79..8bfd19824 100644
--- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/QQ.kt
+++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/QQ.kt
@@ -11,7 +11,7 @@ import net.mamoe.mirai.data.Profile
 /**
  * QQ 对象.
  * 注意: 一个 [QQ] 实例并不是独立的, 它属于一个 [Bot].
- * 它不能被直接构造. 任何时候都应从 [Bot.getQQ] 或事件中获取.
+ * 它不能被直接构造. 任何时候都应从 [Bot.getFriend] 或事件中获取.
  *
  * 对于同一个 [Bot] 任何一个人的 [QQ] 实例都是单一的.
  *
diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/FriendMessage.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/FriendMessage.kt
index c93ecbe6b..065bff68c 100644
--- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/FriendMessage.kt
+++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/FriendMessage.kt
@@ -8,20 +8,9 @@ import net.mamoe.mirai.utils.MiraiInternalAPI
 
 class FriendMessage(
     bot: Bot,
-    /**
-     * 是否是在这次登录之前的消息, 即消息记录
-     */
-    val previous: Boolean,
     override val sender: QQ,
     override val message: MessageChain
 ) : MessagePacket<QQ, QQ>(bot), BroadcastControllable {
-    /**
-     * 是否应被自动广播. 此为内部 API
-     */
-    @MiraiInternalAPI
-    override val shouldBroadcast: Boolean
-        get() = !previous
-
     override val subject: QQ get() = sender
 
     override fun toString(): String = "FriendMessage(sender=${sender.id}, message=$message)"
diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/MessagePacket.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/MessagePacket.kt
index 8745f1564..be4a6b6e4 100644
--- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/MessagePacket.kt
+++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/MessagePacket.kt
@@ -4,7 +4,9 @@ package net.mamoe.mirai.message
 
 import kotlinx.io.core.ByteReadPacket
 import net.mamoe.mirai.Bot
-import net.mamoe.mirai.contact.*
+import net.mamoe.mirai.contact.Contact
+import net.mamoe.mirai.contact.Group
+import net.mamoe.mirai.contact.QQ
 import net.mamoe.mirai.data.EventPacket
 import net.mamoe.mirai.event.events.BotEvent
 import net.mamoe.mirai.message.data.*
@@ -71,12 +73,19 @@ abstract class MessagePacketBase<TSender : QQ, TSubject : Contact>(_bot: Bot) :
 
     // region Image download
     suspend inline fun Image.downloadAsByteArray(): ByteArray = bot.run { downloadAsByteArray() }
+
     suspend inline fun Image.download(): ByteReadPacket = bot.run { download() }
     // endregion
 
-    fun At.qq(): QQ = bot.getQQ(this.target)
+    @Deprecated(message = "这个函数有歧义, 将在不久后删除", replaceWith = ReplaceWith("bot.getFriend(this.target)"))
+    fun At.qq(): QQ = bot.getFriend(this.target)
 
-    fun Int.qq(): QQ = bot.getQQ(this.coerceAtLeastOrFail(0).toLong())
-    fun Long.qq(): QQ = bot.getQQ(this.coerceAtLeastOrFail(0))
+    @Deprecated(message = "这个函数有歧义, 将在不久后删除", replaceWith = ReplaceWith("bot.getFriend(this.toLong())"))
+    fun Int.qq(): QQ = bot.getFriend(this.coerceAtLeastOrFail(0).toLong())
 
+    @Deprecated(message = "这个函数有歧义, 将在不久后删除", replaceWith = ReplaceWith("bot.getFriend(this)"))
+    fun Long.qq(): QQ = bot.getFriend(this.coerceAtLeastOrFail(0))
+
+    @Deprecated(message = "这个函数有歧义, 将在不久后删除", replaceWith = ReplaceWith("bot.getGroup(this)"))
+    fun Long.group(): Group = bot.getGroup(this)
 }
\ No newline at end of file
diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/io/InputUtils.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/io/InputUtils.kt
index 1a0527a9f..4cde854c4 100644
--- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/io/InputUtils.kt
+++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/io/InputUtils.kt
@@ -34,7 +34,7 @@ fun ByteReadPacket.transferTo(outputStream: OutputStream) {
     }
 }
 
-fun <R> ByteReadPacket.useBytes(
+inline fun <R> ByteReadPacket.useBytes(
     n: Int = remaining.toInt(),//not that safe but adequate
     block: (data: ByteArray, length: Int) -> R
 ): R = ByteArrayPool.useInstance {
diff --git a/mirai-japt/src/main/kotlin/net/mamoe/mirai/japt/internal/BlockingBotImpl.kt b/mirai-japt/src/main/kotlin/net/mamoe/mirai/japt/internal/BlockingBotImpl.kt
index 0af6a97c7..a49eec53b 100644
--- a/mirai-japt/src/main/kotlin/net/mamoe/mirai/japt/internal/BlockingBotImpl.kt
+++ b/mirai-japt/src/main/kotlin/net/mamoe/mirai/japt/internal/BlockingBotImpl.kt
@@ -23,7 +23,7 @@ internal class BlockingBotImpl(private val bot: Bot) : BlockingBot {
     @UseExperimental(MiraiInternalAPI::class)
     override fun getQQs(): List<BlockingQQ> = bot.qqs.delegate.toList().map { it.blocking() }
 
-    override fun getQQ(id: Long): BlockingQQ = bot.getQQ(id).blocking()
+    override fun getQQ(id: Long): BlockingQQ = bot.getFriend(id).blocking()
     @UseExperimental(MiraiInternalAPI::class)
     override fun getGroups(): List<BlockingGroup> = bot.groups.delegate.toList().map { it.blocking() }